Skip to main content

Cheapest Flight Within K Stops - LeetCode Daily Challenge

Aakash Verma

Problem Statement

There are n cities connected by some number of flights. You are given an array flights where flights[i] = [fromi, toi, pricei] indicates that there is a flight from city fromi to city toi with cost pricei.

You are also given three integers srcdst, and k, return the cheapest price from src to dst with at most k stops. If there is no such route, return -1.

Example 1

Input: n = 8, flights = [[0,1,1],[0,5,5],[1,2,2],[2,3,1],[3,4,1],[4,6,6],[5,3,4],[5,7,2],[7,4,5]], src = 0, dst = 6, k = 3
Output: 16
Explanation: 
The graph is shown above.
The optimal path with at most 3 stop from city 0 to 3 is 0 -> 5 -> 3 -> 4 -> 6 with minimum cost of 16.
Note that the path through cities [0,1,2,3,4,6] is cheaper but is invalid because it uses 4 stops.

Example 2

Input: n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1
Output: 700
Explanation:
The optimal path with at most 1 stop from city 0 to 3 is marked in red and has cost 100 + 600 = 700.
Note that the path through cities [0,1,2,3] is cheaper but is invalid because it uses 2 stops.

Try here before watching the video.

Video Explanation

Java Code

class Pair {
    int node, distance;
    public Pair(int node, int distance) {
        this.node = node;
        this.distance = distance;
    }
}
class Node {
    int node, distance, stops;
    public Node(int node, int distance, int stops) {
        this.node = node;
        this.distance = distance;
        this.stops = stops;
    }
}
class Solution {
    private List<List<Pair>> buildGraph(int[][] flights, int n) {
        List<List<Pair>> graph = new ArrayList<>();
        for(int i = 0; i < n; i++) {
            graph.add(new ArrayList<>());
        }
        for(int[] flight : flights) {
            graph.get(flight[0]).add(new Pair(flight[1], flight[2]));
        }
        return graph;
    }
    public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
        List<List<Pair>> graph = buildGraph(flights, n);
        int[] distance = new int[n];
        int[] stops = new int[n];
        Arrays.fill(distance, Integer.MAX_VALUE);
        Arrays.fill(stops, Integer.MAX_VALUE);
        PriorityQueue<Node> minHeap = new PriorityQueue<>((node1, node2) -> node1.distance - node2.distance);

        distance[src] = 0;
        stops[src] = 0;
        minHeap.add(new Node(src, distance[src], stops[src]));

        while(!minHeap.isEmpty()) {
            Node curr = minHeap.poll();
            int currNode = curr.node;
            int currDistance = curr.distance;
            int currStops = curr.stops;

            if(currNode == dst) return currDistance;

            if(currStops == k + 1) continue;

            for(Pair pair : graph.get(currNode)) {
                int nbrNode = pair.node;
                int nbrDistance = pair.distance;
                if((currDistance + nbrDistance) < distance[nbrNode]) {
                    distance[nbrNode] = currDistance + nbrDistance;
                    stops[nbrNode] = currStops + 1;
                    minHeap.add(new Node(nbrNode, distance[nbrNode], stops[nbrNode]));
                } else if((currStops + 1) < stops[nbrNode]) {
                    minHeap.add(new Node(nbrNode, currDistance + nbrDistance, currStops + 1));
                }
            }
        }
        return -1;
    }
}

C++ Code

class Node {
public:
    int node, distance, stops;
    Node(int node, int distance, int stops) {
        this->node = node;
        this->distance = distance;
        this->stops = stops;
    }
};

class Solution {
public:

    struct comparator {
		bool operator() (Node a, Node b) {
			return a.distance > b.distance;
		}
	};

    vector<vector<pair<int, int>>> buildGraph(int n, vector<vector<int>>& flights) {
        vector<vector<pair<int, int>>> graph;
        for(int i = 0; i < n; i++) {
            vector<pair<int, int>> v;
            graph.push_back(v);
        }
        for(auto flight : flights) {
            graph[flight[0]].push_back(make_pair(flight[1], flight[2]));
        }
        return graph;
    }

    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
        vector<vector<pair<int, int>>> graph = buildGraph(n, flights);
        priority_queue<Node, vector<Node>, comparator> minHeap;

        vector<int> distance(n, INT_MAX);
        vector<int> stops(n, INT_MAX);

        distance[src] = 0;
        stops[src] = 0;
        minHeap.push(Node(src, 0, 0));

        while(!minHeap.empty()) {
            Node curr = minHeap.top();
            minHeap.pop();
            int currNode = curr.node;
            int currDistance = curr.distance;
            int currStops = curr.stops;

            if(currNode == dst) return currDistance;

            if(currStops == k + 1) continue;

            for(auto pair : graph[currNode]) {
                int nbrNode = pair.first;
                int nbrDistance = pair.second;
                
                if(currDistance + nbrDistance < distance[nbrNode]) {
                    distance[nbrNode] = currDistance + nbrDistance;
                    stops[nbrNode] = currStops + 1;
                    minHeap.push(Node(nbrNode, distance[nbrNode], stops[nbrNode]));
                } else if(currStops + 1 < stops[nbrNode]) {
                    minHeap.push(Node(nbrNode, currDistance + nbrDistance, currStops + 1));
                }
            }
        }
        return -1;
    }
};

Python Code

class Solution:
    def build_graph(n, flights):
        graph = []
        for i in range(n):
            graph.append(list()) # graph = [[], [], [], [], []]
        for flight in flights:
            graph[flight[0]].append((flight[1], flight[2]))
        return graph

    def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
        graph = Solution.build_graph(n, flights)
        min_heap = []

        distance = [math.inf] * n
        stops = [math.inf] * n

        distance[src] = 0
        stops[src] = 0
        heappush(min_heap, (0, 0, src))

        while min_heap:
            curr_dist, curr_stop, curr_node = heappop(min_heap)

            if curr_node == dst:
                return curr_dist

            if curr_stop == k + 1: 
                continue
            
            for nbr, dist in graph[curr_node]:
                if curr_dist + dist < distance[nbr]:
                    distance[nbr] = curr_dist + dist
                    stops[nbr] = curr_stop + 1
                    heappush(min_heap, (distance[nbr], stops[nbr], nbr))
                elif curr_stop + 1 < stops[nbr]:
                    heappush(min_heap, (curr_dist + dist, curr_stop + 1, nbr))
        return -1

Go Code

type Pair struct {
	node     int
	distance int
}

type Node struct {
	node     int
	distance int
	stops    int
}

type MinHeap []Node

func (h MinHeap) Len() int           { return len(h) }
func (h MinHeap) Less(i, j int) bool { return h[i].distance < h[j].distance }
func (h MinHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *MinHeap) Push(x interface{}) {
	*h = append(*h, x.(Node))
}

func (h *MinHeap) Pop() interface{} {
	old := *h
	n := len(old)
	item := old[n-1]
	*h = old[0 : n-1]
	return item
}

func buildGraph(n int, flights [][]int) [][]Pair {
	graph := make([][]Pair, n)
	for _, flight := range flights {
		start, end, distance := flight[0], flight[1], flight[2]
		graph[start] = append(graph[start], Pair{end, distance})
	}
	return graph
}

func findCheapestPrice(n int, flights [][]int, src int, dst int, k int) int {
	graph := buildGraph(n, flights)
	distance := make([]int, n)
	stops := make([]int, n)
	for i := range distance {
		distance[i] = int(1e9)
		stops[i] = int(1e9)
	}
	minHeap := &MinHeap{}
	heap.Init(minHeap)

	distance[src] = 0
	stops[src] = 0
	heap.Push(minHeap, Node{src, distance[src], stops[src]})

	for minHeap.Len() > 0 {
		curr := heap.Pop(minHeap).(Node)
		currNode := curr.node
		currDistance := curr.distance
		currStops := curr.stops

		if currNode == dst {
			return currDistance
		}

		if currStops == k+1 {
			continue
		}

		for _, pair := range graph[currNode] {
			nbrNode := pair.node
			nbrDistance := pair.distance

			newDistance := currDistance + nbrDistance
			newStops := currStops + 1

			if newDistance < distance[nbrNode] {
				distance[nbrNode] = newDistance
				stops[nbrNode] = newStops
				heap.Push(minHeap, Node{nbrNode, newDistance, newStops})
			} else if newStops < stops[nbrNode] {
				heap.Push(minHeap, Node{nbrNode, newDistance, newStops})
			}
		}
	}
	return -1
}

Complexity Analysis

Time Complexity: O(V log V)
Space Complexity: O(E + V),
where E is the number of edges and V is the number of vertices.