中级农民
- 积分
- 109
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2015-1-14
- 最后登录
- 1970-1-1
|
6/14 https://leetcode.com/problems/cheapest-flights-within-k-stops/
又是动规 果然周末的题都比较难吗。。。
1) DFS w/ Memorization 注意要存进cache的是src + k而不是src+dst,lz在这里浪费了好多时间 ==
- var findCheapestPrice = function(n, flights, src, dst, K) {
- if(!n || !flights || !flights.length) return 0;
- const flightsArr = [...Array(n).keys()].map(key => new Array(n));
- for(let i=0; i<flights.length; i++) {
- const [s, d, p] = flights[i];
- flightsArr[s][d] = p;
- }
- let cache = [...Array(n).keys()].map(key => new Array(K));
- var findCheapestPriceHelper = function(s, d, k) {
- if(s === d) return 0;
- if(!k) return flightsArr[s][d] || Number.MAX_SAFE_INTEGER;
- if(cache[s][k]) return cache[s][k];
- let min = Number.MAX_SAFE_INTEGER;
- for(let j=0; j<n; j++) {
- if(flightsArr[s][j]) {
- min = Math.min(min, flightsArr[s][j] + findCheapestPriceHelper(j, d, k-1));
- }
- }
- cache[s][k] = min;
- return min;
- }
- let res = findCheapestPriceHelper(src, dst, K);
- return res === Number.MAX_SAFE_INTEGER ? -1 : res;
- };
复制代码
Time: O(|F| + n^2*k);
Space: O(n^2 + n * k);
2) Dijkstra Algorithm
JS没有内置的堆伤不起,每次都要辛辛苦苦自己写。这里跟普通Dijkstra不太一样的是不仅需要比较price,如果某个城市的stop比之前遍历过的要少的话也要重新加进堆里,而且注意在更新visited数组时,只更新stop/price到更小的值,不要两个一起更新不然会把一些不不要的组合加入堆里导致超时(别问我为什么知道==)
- var findCheapestPrice = function(n, flights, src, dst, K) {
- if(!n || !flights || !flights.length) return 0;
- const flightsArr = new Array(n);
- for(let i=0; i<flights.length; i++) {
- const [s, d, p] = flights[i];
- if(!flightsArr[s]) flightsArr[s] = {};
- flightsArr[s][d] = p;
- }
- let visited = new Array(n), stop=0, res = Number.MAX_SAFE_INTEGER;
- visited[src] = [0, 0]; // [stop, price]
- let mh = new minHeap();
- mh.push([0, -1, src]);
- while(mh.size >0) {
- const [price, stop, city] = mh.pop();
- if(city == dst) res = Math.min(res, price);
- else if(stop<K && flightsArr[city]) {
- Object.entries(flightsArr[city]).forEach(([d, p]) => {
- if(visited[d] && visited[d][0] <= stop+1 && visited[d][1] <= price+p) return;
- if(!visited[d]) visited[d] = [stop+1, price+p];
- else {
- visited[d][1] = Math.min(price+p, visited[d][1]);
- visited[d][0] = Math.min(stop+1, visited[d][0]);
- }
- mh.push([price+p, stop+1, d]);
- })
- }
- }
- return res === Number.MAX_SAFE_INTEGER ? -1 : res;
- };
- class minHeap {
- constructor() {
- this.list = [];
- this.size = 0;
- }
-
- push(val) {
- this.list.push(val);
- this.siftUp(val, this.size);
- this.size++;
- }
-
- siftUp(val, pos) {
- let parent = Math.floor((pos-1)/2);
- while(parent >= 0 && val[0] < this.list[parent][0]) {
- this.list[pos] = this.list[parent];
- pos = parent;
- parent = Math.floor((pos-1)/2);
- }
- this.list[pos] = val;
- }
-
- pop() {
- let res = this.list[0];
- this.size--;
- this.list[0] = this.list[this.size];
- this.list.pop();
- if(this.size > 1) this.siftDown(this.list[0], 0);
- return res;
- }
-
- siftDown(val, pos) {
- let child = 2 * pos + 2 < this.size && this.list[2*pos+2][0] < this.list[2*pos+1][0] ? 2*pos+2 : 2*pos+1;
- while(child<this.size && this.list[child]<this.list[pos]) {
- this.list[pos] = this.list[child];
- pos = child;
- child = 2 * pos + 2 < this.size && this.list[2*pos+2][0] < this.list[2*pos+1][0] ? 2*pos+2 : 2*pos+1;
- }
- this.list[pos] = val;
- }
- }
复制代码
T: O((|F|+n) * logn);
S: O(n ^ 2);
感觉Graph问题的Complexity还是有点tricky的,不知道大家有什么好的方法吗? |
|