当前位置:网站首页>【871. 最低加油次数】
【871. 最低加油次数】
2022-07-02 19:10:00 【千北@】
来源:力扣(LeetCode)
描述:
汽车从起点出发驶向目的地,该目的地位于出发位置东面 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] <= 109
- 0 <= stations.length <= 500
- 0 < stations[0][0] < stations[1][0] < … < stations[stations.length-1][0] < target
方法一:动态规划
由于数组 stations
按照加油站的位置非递减排序,因此从左到右遍历数组 stations
的过程中,当遍历到一个加油站时,位置小于该加油站的所有加油站都已经被遍历过。
用 n 表示数组 stations
的长度,即加油站的个数。最多可以加油 n 次,为了得到可以到达目的地的最少加油次数,需要计算每个加油次数对应的最大行驶英里数,然后得到最大行驶英里数大于等于 target 的最少加油次数。
用 dp[i]
表示加油 i 次的最大行驶英里数。由于初始时汽油量是 startFuel
升,可以行驶 startFuel
英里,因此 dp[0] = startFuel
。
当遍历到加油站 stations[i]
时,假设在到达该加油站之前已经加油 j 次,其中 0 ≤ j ≤ i
,则只有当 dp[j] ≥ stations[i][0]
时才能在加油 jj 次的情况下到达加油站 stations[i]
的位置,在加油站 stations[i]
加油之后,共加油 j + 1 次,可以行驶的英里数是 dp[j] + stations[i][1]
。遍历满足 0 ≤ j≤ i
且 dp[j] ≥ stations[i][0]
的每个下标 j,计算 dp[j+1] 的最大值。
当遍历到加油站 stations[i]
时,对于每个符合要求的下标 j,计算 dp[ j + 1]
时都是将加油站 stations[i]
作为最后一次加油的加油站。为了确保每个 dp[j+1]
的计算中,加油站 stations[i]
只会被计算一次,应该按照从大到小的顺序遍历下标 j。
以示例 3 为例。对于加油站 stations[2]
计算之后 dp[2] = 100
。对于加油站 stations[3]
计算的过程中会将 dp[2] 的值更新为 110 ,如果在计算 dp[3] 之前计算 dp[2],则 dp[3] 的值将被错误地计算为 dp[2] + stations[3][1] = 150。只有当从大到小遍历下标 j 时,才能得到 dp[3] = 140 的正确结果。
当所有的加油站遍历结束之后,遍历 dp,寻找使得 dp[i] ≥ target 的最小下标 i 并返回。如果不存在这样的下标,则无法到达目的地,返回 −1。
代码:
class Solution {
public:
int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
int n = stations.size();
vector<long> dp(n + 1);
dp[0] = startFuel;
for (int i = 0; i < n; i++) {
for (int j = i; j >= 0; j--) {
if (dp[j] >= stations[i][0]) {
dp[j + 1] = max(dp[j + 1], dp[j] + stations[i][1]);
}
}
}
for (int i = 0; i <= n; i++) {
if (dp[i] >= target) {
return i;
}
}
return -1;
}
};
执行用时:84 ms, 在所有 C++ 提交中击败了40.81%的用户
内存消耗:15.6 MB, 在所有 C++ 提交中击败了92.31%的用户
复杂度分析
时间复杂度:O(n2) ,其中 n 是数组 stations 的长度。动态规划的状态数是 O(n),每个状态需要 O(n) 的时间计算,因此时间复杂度是 O(n2)。
空间复杂度: O(n),其中 n 是数组 stations 的长度。需要创建长度为 n + 1 的数组 dp。
方法二:贪心
用 n 表示数组 stations 的长度,即加油站的个数。行驶的过程中依次到达 n + 1 个位置,分别是 n 个加油站和目的地。为了得到最少加油次数,应该在确保每个位置都能到达的前提下,选择最大加油量的加油站加油。
为了得到已经到达过的加油站中的最大加油量,需要使用优先队列记录所有已经到达过的加油站的加油量,优先队列中的最大元素位于队首,即每次从优先队列中取出的元素都是优先队列中的最大元素。
从左到右遍历数组 stations,对于每个加油站,首先判断该位置是否可以达到,然后将当前加油站的加油量添加到优先队列中。对于目的地,则只需要判断是否可以达到。
具体做法如下。
- 计算当前位置(加油站或目的地)与上一个位置的距离之差,根据该距离之差得到从上一个位置行驶到当前位置需要使用的汽油量,将使用的汽油量从剩余的汽油量中减去。
- 如果剩余的汽油量小于0,则表示在不加油的情况下无法从上一个位置行驶到当前位置,需要加油。取出优先队列中的最大元素加到剩余的汽油量,并将加油次数加 1,重复该操作直到剩余的汽油量大于等于 0 或优先队列变为空。
- 如果优先队列变为空时,剩余的汽油量仍小于0,则表示在所有经过的加油站加油之后仍然无法到达当前位置,返回 −1。
- 如果当前位置是加油站,则将当前加油站的加油量添加到优先队列中,并使用当前位置更新上一个位置。
如果无法到达目的地,则在遍历过程中返回 −1。如果遍历结束仍未返回−1,则可以到达目的地,返回加油次数。
代码:
class Solution {
public:
int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
priority_queue<int> pq;
int ans = 0, prev = 0, fuel = startFuel;
int n = stations.size();
for (int i = 0; i <= n; i++) {
int curr = i < n ? stations[i][0] : target;
fuel -= curr - prev;
while (fuel < 0 && !pq.empty()) {
fuel += pq.top();
pq.pop();
ans++;
}
if (fuel < 0) {
return -1;
}
if (i < n) {
pq.emplace(stations[i][1]);
prev = curr;
}
}
return ans;
}
};
执行用时:20 ms, 在所有 C++ 提交中击败了91.24%的用户
内存消耗:15.6 MB, 在所有 C++ 提交中击败了91.88%的用户
边栏推荐
- 【Hot100】21. Merge two ordered linked lists
- upload-labs
- AcWing 1127. Sweet butter solution (shortest path SPFA)
- 自動生成VGG圖像注釋文件
- [real case] trap of program design - beware of large data
- 测试人员如何做不漏测?这7点就够了
- [Chongqing Guangdong education] reference materials for labor education of college students in Nanjing University
- RPD出品:Superpower Squad 保姆级攻略
- Zabbix5 client installation and configuration
- 多端小程序开发有什么好处?覆盖百度小程序抖音小程序微信小程序开发,抢占多平台流量红利
猜你喜欢
Conscience summary! Jupyter notebook from Xiaobai to master, the nanny tutorial is coming!
Automatically generate VGg image annotation file
CRM客户关系管理系统
Build a master-slave mode cluster redis
Development skills of rxjs observable custom operator
450 Shenxin Mianjing 1
HDL design peripheral tools to reduce errors and help you take off!
笔记本安装TIA博途V17后出现蓝屏的解决办法
CRM Customer Relationship Management System
浏览器缓存机制概述
随机推荐
AcWing 1129. Heat wave solution (shortest path SPFA)
451 implementation of memcpy, memmove and memset
Detailed explanation of VBScript (I)
数据库模式笔记 --- 如何在开发中选择合适的数据库+关系型数据库是谁发明的?
Motivation! Big Liangshan boy a remporté le prix Zhibo! Un article de remerciement pour les internautes qui pleurent
Start practicing calligraphy
AcWing 903. Expensive bride price solution (the shortest path - building map, Dijkstra)
Kt148a voice chip IC software reference code c language, first-line serial port
sql-labs
为什么我对流程情有独钟?
How to avoid duplicate data in gaobingfa?
Self-Improvement! Daliangshan boys all award Zhibo! Thank you for your paper
编写完10万行代码,我发了篇长文吐槽Rust
Cs5268 perfectly replaces ag9321mcq typec multi in one docking station solution
分享几个图床网址,便于大家分享图片
Solution: vs2017 cannot open the source file stdio h main. H header document [easy to understand]
VBScript详解(一)
NMF-matlab
CheckListBox control usage summary
Génération automatique de fichiers d'annotation d'images vgg