leetcode134. 加油站

法一:先计算 rest[i] = gas[i] - cost[i] , 判断从某个位置开始的累和是否<0。时间打败了5.17%🤡
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int len = gas.length;
if(len == 1 && gas[0] >= cost[0]) return 0;
int[] rest = new int[len];
for(int i = 0;i < len;++i) rest[i] = gas[i] - cost[i];
for(int i = 0;i < len;++i){
if(rest[i] <= 0) continue;
int sum = rest[i];
for(int j = (i + 1) % len;j != i;j = (j + 1) % len){
sum += rest[j];
if(sum < 0) break;
}
if(sum < 0) continue;
return i;
}
return -1;
}
}
法二:贪心

class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n = gas.length;
int i = 0;
while (i < n) {
int curGas = 0; // 当前剩余油量
int cnt = 0; // 成功走过的站点数
// 模拟从i出发走一圈
while (cnt < n) {
int j = (i + cnt) % n; // 当前所在站点
curGas += gas[j] - cost[j];
if (curGas < 0) break; // 从i出发无法走完全程
cnt++;
}
if (cnt == n) return i;// 成功走完一圈
else i = i + cnt + 1;// 核心优化:从i出发最远能到达i+cnt,那么i和i+cnt之间的点都可以跳过
}
return -1;
}
}
法三:一次遍历贪心(推荐)
算法思路:
- 全局判断:如果总的汽油量小于总消耗量(
sum(gas) < sum(cost)),那么无论从哪里出发都不可能完成全程,直接返回-1 - 局部判断:维护一个当前油量
curTank。从站点0开始遍历,将每个站点的净收益(gas[i] - cost[i])累加到curTank。 - 贪心选择起点:如果在某个站点
i,curTank变为负数,说明从之前记录的start起点无法到达i+1。那么起点绝不可能是start到i之间的任何一点,我们将起点候选更新为i+1,同时将curTank归零,重新计算 - 由于第一步已经保证了有解,遍历结束后
start就是唯一解。
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
// totalTank: 记录跑完整个环路,油箱里最终剩下的总油量。
// 如果它是负数,说明所有加油站的油加起来都不够跑完全程的消耗,肯定无解[5](@ref)。
int totalTank = 0;
// curTank: 记录从当前候选起点(start)出发,开到当前位置时,油箱里剩余的油量。
// 它是我们判断当前起点是否可行的“临时钱包”[7](@ref)。
int curTank = 0;
// start: 我们认为最有可能作为成功起点的加油站编号。一开始我们假设从0号站出发。
int start = 0;
// 开始逐个遍历每一个加油站
for (int i = 0; i < gas.length; i++) {
// 计算经过当前加油站i的“净收益”:加油量 - 到下一站的消耗量。
int netGas = gas[i] - cost[i];
// 将本站的净收益累加到总油量池中,用于最后判断全局是否有解。
totalTank += netGas;
// 将本站的净收益累加到当前油箱,看从当前起点出发,能否顺利开到下一站。
curTank += netGas;
// **关键判断**:如果当前油箱油量小于0了,说明了一件重要的事:
// “从我们当前选择的起点`start`出发,最远只能开到本站i,无法开到下一站i+1。”
if (curTank < 0) {
// 既然从`start`出发连i+1都到不了,那么`start`肯定不是正确起点。
// 并且,一个非常重要的推论是:从`start`到`i`之间的任何一个站点,也都不能作为起点!
// 为什么呢?想象一下:从`start`出发到`i`这段路,你甚至可能还攒下了一些油(curTank曾经是正的),这都失败了。如果从一个更靠后、基础更差的中间点出发,肯定更无法弥补在i站出现的油量赤字[4,7](@ref)。
// 所以,我们不需要再尝试`start`和`i`之间的点,而是直接“跳跃”到下一个最有可能的地方:i+1号站,把它作为新的候选起点。
start = i + 1;
// 既然更换了起点,我们就要清空“临时钱包”,从0开始重新计算从这个新起点出发的油量情况。
curTank = 0;
}
}
// 循环结束后,我们遍历了所有加油站,也找到了一个候选起点`start`。
// 现在需要进行最终裁决:全局油量是否足够?
// - 如果总油量totalTank >= 0,说明整个路程在油量上是可行的。那么根据题目保证,我们找到的`start`就是唯一正确的起点[1](@ref)。
// - 如果总油量totalTank < 0,说明全世界所有的油加起来都不够用,直接返回-1表示无解[5](@ref)。
return totalTank >= 0 ? start : -1;
}
}
浙公网安备 33010602011771号