开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情
最低加油次数
汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。
沿途有加油站,每个 station[i] 代表一个加油站,它位于出发位置东面 station[i][0] 英里处,并且有 station[i][1] 升汽油。
假设汽车油箱的容量是无限的,其中最初有 startFuel 升燃料。它每行驶 1 英里就会用掉 1 升汽油。
当汽车到达加油站时,它可能停下来加油,将所有汽油从加油站转移到汽车中。
为了到达目的地,汽车所必要的最低加油次数是多少?如果无法到达目的地,则返回 -1 。
注意:如果汽车到达加油站时剩余燃料为 0,它仍然可以在那里加油。如果汽车到达目的地时剩余燃料为 0,仍然认为它已经到达目的地。
示例1:
输入: target = 1, startFuel = 1, stations = []
输出: 0
解释: 我们可以在不加油的情况下到达目的地。
示例2:
输入:target = 100, startFuel = 1, stations = [[10,100]]
输出:-1
解释:我们无法抵达目的地,甚至无法到达第一个加油站。
示例3:
输入:target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]]
输出:2
解释:
我们出发时有 10 升燃料。
我们开车来到距起点 10 英里处的加油站,消耗 10 升燃料。将汽油从 0 升加到 60 升。
然后,我们从 10 英里处的加油站开到 60 英里处的加油站(消耗 50 升燃料),
并将汽油从 10 升加到 50 升。然后我们开车抵达目的地。
我们沿途在1两个加油站停靠,所以返回 2 。
提示:
- 1 <= target, startFuel, stations[i][1] <= 10^9
- 0 <= stations.length <= 500
- 0 < stations[0][0] < stations[1][0] < ... < stations[stations.length-1][0] < target
解题思路:
首先想象车内的油可以支撑你跑多远,然后将可以到达的加油站都装入大顶堆,用startFuel记录你车里面的油,并判断是否大于target。
当startFuel大于等于target的时候,退出while。或者当大顶堆里面为空时,说明车内的油无法到达目的地(此时车在每一个经过的加油站都加满了油,但还是不够)。
我的答案:
/**
* @param {number} target
* @param {number} startFuel
* @param {number[][]} stations
* @return {number}
*/
var minRefuelStops = function(target, startFuel, stations) {
let heap = [];
// fuel表示当前时刻油箱还有多少油
let fuel = startFuel, staNum = 0, road = 0;
//将目的地当做最后一个加油站,该加油站的燃料为0
stations.push([target,0]);
//判断能够到达各个加油站
for(let i=0;i<stations.length;i++){
//判断能否到达第i个加油站
road = stations[i][0];
let heapR = 0;
while(road>fuel){
heapR = heapPop(heap);
// 若堆为空,说明当前节点之前的所有加油站中的油都已经加入了,此时不能到达第i站加油站了,因此不能到达目的地,返回-1;
if(heapR===null){return -1;}
fuel += heapR;
staNum++;
}
//若能到达将该加油站的油添加进堆中
heapAdd(heap, stations[i][1]);
}
return staNum;
};
// 大堆,向堆heap中添加元素,heap是一个完全二叉树
function heapAdd(heap, n){
heap.push(n);
//t节点的父节点np
let t = heap.length-1, np = ((t-1)-(t-1)%2)/2, tempt;
while(t>0){
if(heap[np]<heap[t]){
tempt = heap[np];
heap[np] = heap[t];
heap[t] = tempt;
t = np;
np = ((t-1)-(t-1)%2)/2;
}else{
break;
}
}
// console.log(heap)
return;
}
// 大堆,从堆heap中取出堆顶元素,heap是一个完全二叉树
function heapPop(heap){
if(heap.length<=0) return null;
// 删除堆顶元素,保留在rn中
let rn = heap[0];
heap[0] = heap[heap.length - 1];
heap.splice(heap.length-1,1);
//调整堆, n表示当前节点,rL表示n的左子节点,r表示n的子节点中值最大的那个节点
let rL = 1, r, n = 0;
while(rL<=heap.length -1){
r = rL;
if(rL+1<=heap.length-1 && heap[rL]<heap[rL+1]){
r = rL + 1;
}
if(heap[n]<heap[r]){
temp = heap[n];
heap[n] = heap[r];
heap[r] = temp;
n = r;
rL = 2*n + 1;
}else{
break;
}
}
// console.log(rn)
return rn;
}
最后
如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )