题目
中等
相关标签
在一条环路上有 n
个加油站,其中第 i
个加油站有汽油 gas[i]
升。
你有一辆油箱容量无限的的汽车,从第i
个加油站开往第i+1
个加油站需要消耗汽油 cost[i]
升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas
和 cost
,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1
。如果存在解,则 保证 它是 唯一 的。
示例 1:
输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2] 输出: 3 解释: 从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油 开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油 开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油 开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油 开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油 开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。 因此,3 可为起始索引。
示例 2:
输入: gas = [2,3,4], cost = [3,4,3] 输出: -1 解释: 你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。 我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油 开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油 开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油 你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。 因此,无论怎样,你都不可能绕环路行驶一周。
提示:
gas.length == n
cost.length == n
1 <= n <= 105
0 <= gas[i], cost[i] <= 104
思路和解题方法 一(暴力)
- 目标是判断给定的汽油站能否构成一个环路,使得可以从某个站点出发,顺时针往前绕一圈返回该站点。每个站点有两个属性:gas[i] 表示在该站点加油可获得的油量,cost[i] 表示从该站点到下一个站点需要消耗的油量。
- 为了判断是否可以行驶一圈,我们可以模拟一遍整个过程。假设从第 i 个站点出发,开始时剩余油量为 gas[i]−cost[i],依次到达第 i+1,i+2,...,n−1,0,1,...,i−1 个站点,每经过一个站点,就用消耗的油量减去加入的油量,同时记录当前的剩余油量。如果最后回到了起点且剩余油量不小于 0,则说明可以完成一次环形行驶。
复杂度
时间复杂度:
O(n*n)
时间复杂度: O(n*n),n 是站点数,因为每个站点都可能做一次循环检查。
空间复杂度
O(1)
空间复杂度: O(1),只需要常数个变量记录当前状态即可。
c++ 代码 一 (暴力)
cpp
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
for (int i = 0; i < cost.size(); i++) { // 对于每一个点,以它为起点做一次循环检查
int rest = gas[i] - cost[i]; // 记录当前点的剩余油量
int index = (i + 1) % cost.size(); // 初始化index指向下一个点
while (rest > 0 && index != i) { // 如果还有油且没有回到起点,就继续往前走
rest += gas[index] - cost[index]; // 更新剩余油量
index = (index + 1) % cost.size();// 更新下一个点
}
if (rest >= 0 && index == i) { // 如果油足够到达终点并回到起点了,就返回起点
return i;
}
}
return -1; // 否则返回-1
}
};
思路和解题方法 二(贪心)
- 当我们遍历每个站点时,我们首先更新curSum和totalSum。curSum是从起始位置到当前位置的累加剩余油量,它等于上一个位置的curSum加上当前站点的剩余油量(gas[i] - cost[i])。totalSum是所有站点的累加剩余油量,它等于上一个位置的totalSum加上当前站点的剩余油量(gas[i] - cost[i])。
- 接下来,我们判断curSum是否小于0,如果小于0,说明从起始位置到达当前位置的路径不可行。因为如果从起始位置开始,累加剩余油量一直小于0,那么无论从哪个位置出发都无法完成一次环形行驶。所以,我们将起始位置更新为当前位置的下一个位置(i + 1),并且重置curSum为0,相当于重新开始计算累加剩余油量。
- 最后,我们在遍历结束后检查totalSum是否小于0。如果totalSum小于0,说明所有站点的累加剩余油量都是负数,即无法完成一次环形行驶,返回-1。否则,我们返回起始位置start,因为凡是能够完成一次环形行驶的情况下,start位置一定是符合条件的。
复杂度
时间复杂度:
O(n)
时间复杂度: O(n),其中n是站点数。遍历一次所有站点进行累计操作。
空间复杂度
O(1)
空间复杂度: O(1),只需要常数个变量记录当前状态。
c++ 代码 二 (贪心)
cpp
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0; // 当前累加剩余油量
int totalSum = 0; // 总累加剩余油量
int start = 0; // 起始位置
for (int i = 0; i < gas.size(); i++) {
curSum += gas[i] - cost[i]; // 更新当前累加剩余油量
totalSum += gas[i] - cost[i]; // 更新总累加剩余油量
if (curSum < 0) { // 当前累加剩余油量小于0,说明从起始位置到达当前位置的路径不可行
start = i + 1; // 更新起始位置为当前位置的下一个位置
curSum = 0; // 重置当前累加剩余油量为0
}
}
if (totalSum < 0) return -1; // 总累加剩余油量小于0,说明无法完成一次环形行驶,返回-1
return start; // 返回起始位置
}
};
对于这里的解释
cpp
curSum += gas[i] - cost[i]; // 更新当前累加剩余油量
totalSum += gas[i] - cost[i]; // 更新总累加剩余油量
if (curSum < 0) { // 当前累加剩余油量小于0,说明从起始位置到达当前位置的路径不可行
start = i + 1; // 更新起始位置为当前位置的下一个位置
curSum = 0; // 重置当前累加剩余油量为0
}
更新当前累加剩余油量(curSum): curSum从上一个站点累加的剩余油量加上当前站点的剩余油量(gas[i] - cost[i])得到。
更新总累加剩余油量(totalSum): totalSum从上一个站点累加的剩余油量加上当前站点的剩余油量(gas[i] - cost[i])得到。
curSum的作用是判断从起始位置到达当前位置的路径是否可行。如果curSum小于0,说明从起始位置到达当前位置的路径不可行,因为从起始位置开始到当前位置油量一直不足,不可能顺利到达当前位置,更别说从当前位置继续走了。所以我们需要将起始位置更新为当前位置的下一个位置(i+1),并将curSum重置为0,相当于重新开始计算从新的起始位置到哪个位置的路径可行。
totalSum的作用是判断整个环路是否可行。如果totalSum小于0,说明所有站点的总剩余油量是负数,即无法完成一次环形行驶,返回-1即可。
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。