Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

leetcode problem #787 "cheapest flights within k stops"

I am trying to solve LeetCode problem #787, "Cheapest Flights Within K Stops."

"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."

However, I am encountering an issue with a specific testcase:

flights = [[0,1,5],[1,2,5],[0,3,2],[3,1,2],[1,4,1],[4,2,1]], 
n = 5, 
src = 0, 
dst = 2, 
k = 2

The expected answer is 7, but my code is returning 9. I have spent the last 2 hours debugging the code, but I cant seem to find the issue. I would appreciate if someone can point out whats wrong with the code.

code:

class minHeap {
    constructor() {
        this.nodes = []
    }

    enqueue(node, priority, stopsCount) {
        if(this.isEmpty()) {
            this.nodes.push([node, priority, stopsCount])
        } else {
            let added = false;

            for(let i = 0; i < this.nodes.length; i++) {
                if(this.nodes[i][1] > priority) {
                    this.nodes.splice(i, 0, [node, priority, stopsCount])
                    added = true
                    break;
                }
            }

            if(!added) {
                this.nodes.push([node, priority, stopsCount])
            }
        }
    }

    dequeue() {
        return this.nodes.shift()
    }

    isEmpty() {
        return this.nodes.length === 0
    }
}

var findCheapestPrice = function(n, flights, src, dst, k) {
    const graph = {}
    const prices = {}
    for(let i = 0; i < n; i++) {
        graph[i] = []
        if (i == src) {
            prices[i] = 0
        } else {
            prices[i] = Infinity
        }
    }

    for(let [ from, to, price ] of flights) {
        graph[from].push([ to, price ])
    }


    const heap = new minHeap()
    heap.enqueue(src, 0, 0)
    
    while (!heap.isEmpty()) {
        const [ airport, price, stopsCount ] = heap.dequeue()
        
        for (let neighbor of graph[airport]) {
            const [ neighborAirport, neighborPrice ] = neighbor
            const priceToNeighbor = neighborPrice + price
            
            if (prices[neighborAirport] > priceToNeighbor && stopsCount <= k) {
                prices[neighborAirport] = priceToNeighbor
                heap.enqueue(neighborAirport, priceToNeighbor, stopsCount+1)
            }

        }
    }

    
    return prices[dst] == Infinity ? -1 : prices[dst]
};
like image 858
Andrew Kim Avatar asked Sep 14 '25 21:09

Andrew Kim


2 Answers

I don't have enough time to debug exactly what's wrong but I feel something is wrong with your enqueuing priority. Removing that optimization causes the program to work correctly:

class minHeap {
    constructor() {
        this.nodes = []
    }

    enqueue(node, priority, stopsCount) {
        // This now work without the priority.
        this.nodes.push([node, priority, stopsCount]);
    }

    dequeue() {
        return this.nodes.shift()
    }

    isEmpty() {
        return this.nodes.length === 0
    }
}

var findCheapestPrice = function(n, flights, src, dst, k) {
    const graph = {}
    const prices = {}
    for(let i = 0; i < n; i++) {
        graph[i] = []
        if (i == src) {
            prices[i] = 0
        } else {
            prices[i] = Infinity
        }
    }

    for(let [ from, to, price ] of flights) {
        graph[from].push([ to, price ])
    }


    const heap = new minHeap()
    heap.enqueue(src, 0, 0)

    while (!heap.isEmpty()) {
        const [ airport, price, stopsCount ] = heap.dequeue()
        
        for (let neighbor of graph[airport]) {
            const [ neighborAirport, neighborPrice ] = neighbor
            const priceToNeighbor = neighborPrice + price
            
            if (prices[neighborAirport] > priceToNeighbor && stopsCount <= k) {
                prices[neighborAirport] = priceToNeighbor
                heap.enqueue(neighborAirport, priceToNeighbor, stopsCount+1)
            }

        }
    }

    
    return prices[dst] == Infinity ? -1 : prices[dst]
};

const
  flights = [[0,1,5],[1,2,5],[0,3,2],[3,1,2],[1,4,1],[4,2,1]], 
  n = 6, 
  src = 0, 
  dst = 2, 
  k = 2;
console.log(findCheapestPrice(n, flights, src, dst, k));

I tried submitting the above code to LeetCode (sorry about that, I didn't mean to plagarize, just want to test), it passes all test cases.

Update: this fix may work by luck though I cannot find a counter example yet. In fact, I think without the priority, it should work for all cases (see comments below and the other answer). Even with this complicated graph this code works:

enter image description here

like image 179
Luke Vo Avatar answered Sep 16 '25 12:09

Luke Vo


The scheme to update and only enqueue stops prioritised by cost doesn't work in this particular example because the cost to get to airport 4 is set as 5 after 3 stops (including the last): [0,3,2] -> [3,1,2] -> [1,4,1]. But in order to reach airport 2 optimally, we need the interim state where we reach airport 4 with cost 6 but the priority scheme prevents this:

[0,1,5] -> [1,4,1]

I don't believe Dijkstra can be used generally to optimise edge cost to a destination where the number of edges is restricted. Other dynamic programming or graph algorithms can assist with that.

like image 34
גלעד ברקן Avatar answered Sep 16 '25 10:09

גלעד ברקן