题解(优先队列+贪心)
题解转载自溯
前提条件
汽车为什么需要加油?
- 当前油箱中的油不能到达下一个加油站
- 当前油箱中的油不能到达目的地
原理
知道了汽车为什么需要加油之后,我们还必须保证去加油站的次数最少,而且油够用。如何才能保证加油次数最少呢?正向思维不行,我们就用逆向思维,到了加油站之后先不着急考虑是否加油(因为我们不能知道下一个加油站的油量),我们先将加油站放在后备箱里面(假设一下汽车可以装上加油站),沿着路途收集加油站。汽车行驶过程中,我们的汽车油箱的油可能不够支持我们到达下一个加油站或者目的地了,此时我们需要加油,这时我们后备箱收集的加油站就派上用场了,选择最大的加油站加上油即可,如果还要加油,则再选择一个次大的加油站。。。。
简要原理
看完前面的原理可能你觉得太长了,难懂,这里精简一下:这题本题就是让我们消耗加油站,我们将消耗过程转为收集过程。收集完了之后从中选择一个最大的加油站即可。选择最大加油站的过程可以使用优先队列(大根堆)
算法
- 定义 pq(优先队列)为一个保存了驶过加油站油量的最大堆,定义当前油量为 tank。
- 如果当前油量为负数(意味着当前油量不够抵达当前位置),那就必须在驶过的加油站找一个油量储备最大来加油。
- 如果在某个位置油量为负,且没有加油站可用了,那就不可能完成这个任务。
class Solution {
public int minRefuelStops(int target, int startFuel, int[][] stations) {
int tank=startFuel;
//count:加油次数 prev:上一次经过的站点
int count=0;
int prev=0;
//大根堆:顶部最大,用于获取油量最大的油
PriorityQueue<Integer> pq = new PriorityQueue<>((v1,v2)->v2-v1);
for(int i=0;i<stations.length;i++){
int location = stations[i][0];
int capacity = stations[i][1];
//tank:汽车运行到当前location时剩余的油量
tank-=location-prev;
//为什么只有tank<0才加油? 只要tank=0就可以到当前站点,贪心思路
//如果邮箱中油量<0就循环加油直至tank>0,如果油量>0则不需要加油
while(!pq.isEmpty()&&tank<0){
tank+=pq.poll();
count++;
}
if(tank<0) return -1;
//当前加油站的油用于驶向下一个站点 所以驶离当前站点再加
//每遇到一个加油站就将其存入优先队列中
pq.offer(capacity);
//prev:更新上一次经过的站点
prev=location;
}
// 上面的for循环只到最后一个加油站,没有到终点,需要在终点处再做判断
{
tank -= target - prev;
while (!pq.isEmpty() && tank < 0) {
tank += pq.poll();
count++;
}
if (tank < 0) return -1;
}
return count;
}
}