Question:
思路:
这个题两个方法:
1.dp 2.heap
- dp方法我们可以设置mem table.mem[i]. 然后 mem[i] 代表
用I个refuel最远可以走多远.
然后最后结尾的时候只要loop mem[i] 找到最早先大于target 就行.
然后这个dp approach在循环中, 每次我们都是先从小的开始.
for (int i = 0; i < N; ++i)
for (int t = i; t >= 0; --t)
if (dp[t] >= stations[i][0])
dp[t+1] = Math.max(dp[t+1], dp[t] + (long) stations[i][1]);
这个其实就是主要循环的code. update mem table的.
我们按照顺序一个一个处理station.
我们会先判断当前走的最远距离能不能走到第i个station. 如果可以走到, 那我们就更新dp[i+1], 其实dp[i+1] 就是用第i+1个station refuel可以走多远, 为什么是i+1呢, 首先我们的station 0 其实就是一个station. 按理说dp[0] 应该是用station0可以最远走多远, 但是这和我们定义的dp table 实际表达意思不符,dp[0]应该代表不refuel 最远可以走多远, 就是startFuel. 那么, 这里第i个station. 就其实是dp[i+1]这里的使用. 然后dp[i+1] = max(dp[i] + station[1], 这个好理解,直接加上前一个, dp[i+1]) 为什么这里还有个dp[i+1]呢, 难道不是这个永远都没有前面那个大吗?
不是这样的, 每次我们先碰到一个station, dp[i+1]确实=0, 但是我们的inner loop是从i 往 0 循环, 所以. 到后面的loop的时候, 我们会重新判断以前的选择. 就是相当于, 我们又多了一个station 可以在i个refuel 之内 refuel, 就是说我们要判断, 如果我i个stop refuel里可不可以把当前这个加油站考虑进去, 然后如果我考虑进去的话, 那我之前那些加油站我少加一次,换成加这个station, 会不会比我原先加的那些station 总公里数更远.
举个例子就像 我startFuel = 30, 然后station = [[10,10],[20,50]], dp[] = [30,0,0]
在我第二次run loop的时候. dp[1] >= station[1][0]
然后更新dp[2]
接着回到dp[0] = 30 >= station[1][0] = 20
然后再更新一次dp[1], 找一下 refuel 1次可以行驶的最远距离.
这里就相当于, 我们在判断, 我的startFuel是不是也可以直接加station1. 而且我直接加station1 不加 station0 是不是可以走的更远. 这个时候dp[1] = max(dp[1] 这里就是原先用station[0]的值, 和dp[0] + …) 就能理解了
所以dp[] 里存的就是refuel i 次, 可以走的最远距离
class Solution {
public int minRefuelStops(int target, int startFuel, int[][] stations) {
int N = stations.length;
long[] dp = new long[N + 1];
dp[0] = startFuel;
for (int i = 0; i < N; ++i)
for (int t = i; t >= 0; --t)
if (dp[t] >= stations[i][0])
dp[t+1] = Math.max(dp[t+1], dp[t] + (long) stations[i][1]);
else break;
for (int i = 0; i <= N; ++i)
if (dp[i] >= target) return i;
return -1;
}
}
用heap
这个就有点儿偏greedy了. 就是我们想要行驶的最远加油最少, 肯定是我们不到万不得已不加油, 而且要加也得每次加油最多的station. 那首先要想加油, 我们得先能行驶到station才行. 那我们就可以先往target 走, 然后用一个max heap存每个加油站的油. 走到我们没有用必须得加的时候, 我们每次都先加先前经过的油最多的station. 直到我们走到没油,而且经过的station油都加了.还是到不了下一个加油站或者target,那就代表到不了.
class Solution {
public int minRefuelStops(int target, int startFuel, int[][] stations) {
PriorityQueue<Integer> max = new PriorityQueue<>((a,b)->b-a);
int res = 0;
int prevStation = 0;
for(int[] station: stations){
// each time we reduce a station distance, we are actually repeatly reduce a previous sattion distance also, so we need to add it back
startFuel -= (station[0] - prevStation);
while(!max.isEmpty() && startFuel < 0){
startFuel += max.poll();
res++;
}
if(startFuel < 0) return -1;
max.add(station[1]);
prevStation = station[0];
}
// in the last step, still need to check if we can made to target.
startFuel -= (target - prevStation);
while(!max.isEmpty() && startFuel < 0){
startFuel += max.poll();
res++;
}
if(startFuel < 0) return -1;
return res;
}
}