A car travels from a starting position to a destination which is target
miles east of the starting position.html
Along the way, there are gas stations. Each station[i]
represents a gas station that is station[i][0]
miles east of the starting position, and has station[i][1]
liters of gas.git
The car starts with an infinite tank of gas, which initially has startFuel
liters of fuel in it. It uses 1 liter of gas per 1 mile that it drives.github
When the car reaches a gas station, it may stop and refuel, transferring all the gas from the station into the car.数组
What is the least number of refueling stops the car must make in order to reach its destination? If it cannot reach the destination, return -1
.ide
Note that if the car reaches a gas station with 0 fuel left, the car can still refuel there. If the car reaches the destination with 0 fuel left, it is still considered to have arrived.code
Example 1:htm
Input: target = 1, startFuel = 1, stations = [] Output: 0 Explanation: We can reach the target without refueling.
Example 2:blog
Input: target = 100, startFuel = 1, stations = [[10,100]] Output: -1 Explanation: We can't reach the target (or even the first gas station).
Example 3:leetcode
Input: target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]] Output: 2 Explanation: We start with 10 liters of fuel. We drive to position 10, expending 10 liters of fuel. We refuel from 0 liters to 60 liters of gas. Then, we drive from position 10 to position 60 (expending 50 liters of fuel), and refuel from 10 liters to 50 liters of gas. We then drive to and reach the target. We made 2 refueling stops along the way, so we return 2.
Note:get
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
这道题说有一辆小车,须要向东行驶 target 的距离,路上有许多加油站,每一个加油站有两个信息,一个是距离起点的距离,另外一个是能够加的油量,问咱们到达 target 位置最少须要加的油量。咱们能够从第三个例子来分析,开始时有 10 升油,能够到达第一个加油站,此时花掉了 10 升,可是能够补充 60 升,当前的油能够到达其余全部的加油站,因为已经开了 10 迈,因此到达后面的加油站的距离分别为 10,20,和 50。若咱们到最后一个加油站,那离起始位置就有 60 迈了,再加上此加油站提供的 40 升油,直接就能够到达 100 位置,不用再加油了,因此总共只须要加2次油。由此能够看出来其实咱们但愿到达尽量远的加油站的位置,同时最好该加油站中的油也比较多,这样下一次就能到达更远的位置。像这种求极值的问题,十有八九要用动态规划 Dynamic Programming 来作,可是这道题的 dp 定义式并非直接来定义须要的最少加油站的个数,那样定义的话不太好推导出状态转移方程。正确的定义应该是根据加油次数能到达的最远距离,咱们就用一个一维的 dp 数组,其中 dp[i] 表示加了i次油能到达的最远距离,那么最后只要找第一个i值使得 dp[i] 大于等于 target 便可。dp 数组的大小初始化为加油站的个数加1,值均初始化为 startFuel 便可,由于初始的油量能到达的距离是肯定的。如今来推导状态转移方程了,遍历每个加油站,对于每一个遍历到的加油站k,须要再次遍历其以前的全部的加油站i,能到达当前加油站k的条件是当前的 dp[i] 值大于等于加油站k距起点的距离,若大于等于的话,咱们能够更新 dp[i+1] 为 dp[i]+stations[k][1],这样就能够获得最远能到达的距离。当 dp 数组更新完成后,须要再遍历一遍,找到第一个大于等于 target 的 dp[i] 值,并返回i便可,参见代码以下:
解法一:
class Solution { public: int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) { int n = stations.size(); vector<long> dp(n + 1, startFuel); for (int k = 0; k < n; ++k) { for (int i = k; i >= 0 && dp[i] >= stations[k][0]; --i) { dp[i + 1] = max(dp[i + 1], dp[i] + stations[k][1]); } } for (int i = 0; i <= n; ++i) { if (dp[i] >= target) return i; } return -1; } };
这道题还有一个标签是 Heap,说明还能够用堆来作,这里是用最大堆。由于以前也分析了,咱们关心的是在最小的加油次数下能达到的最远距离,那么每一个加油站的油量就是关键因素,能够将全部能到达的加油站根据油量的多少放入最大堆,这样每一次都选择油量最多的加油站去加油,才能尽量的到达最远的地方(若是骄傲没被现实大海冷冷拍下,又怎会懂得要多努力,才走获得远方。。。打住打住,要唱起来了 ^o^)。这里须要一个变量i来记录当前遍历到的加油站的位置,外层循环的终止条件是 startFuel 小于 target,而后在内部也进行循环,若当前加油站的距离小于等于 startFuel,说明能够到达,则把该加油站油量存入最大堆,这个 while 循环的做用就是把全部当前能到达的加油站的油量都加到最大堆中。这样取出的堆顶元素就是最大的油量,也是咱们下一步须要去的地方(最想要去的地方,怎么能在半路就返航?!),假如此时堆为空,则直接返回 -1,表示没法到达 target。不然就把堆顶元素加到 startFuel 上,此时的startFuel 就表示当前能到的最远距离,是否是跟上面的 DP 解法核心思想很相似。因为每次只能去一个加油站,此时结果 res 也自增1,当 startFuel 到达 target 时,结果 res 就是最小的加油次数,参见代码以下:
解法二:
class Solution { public: int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) { int res = 0, i = 0, n = stations.size(); priority_queue<int> pq; for (; startFuel < target; ++res) { while (i < n && stations[i][0] <= startFuel) { pq.push(stations[i++][1]); } if (pq.empty()) return -1; startFuel += pq.top(); pq.pop(); } return res; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/871
参考资料:
https://leetcode.com/problems/minimum-number-of-refueling-stops/