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 src, dst, 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.