一、题目描述
在一条环路上有 n
个加油站,其中第 i
个加油站有汽油 gas[i]
升。
你有一辆油箱容量无限的的汽车,从第 i
个加油站开往第 i+1
个加油站需要消耗汽油 cost[i]
升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas
和 cost
,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1
。如果存在解,则 保证 它是 唯一 的。
二、解题思路
1.由题意得:要判断汽车能否从第 i 个加油站开到第 i+1 个加油站,要计算gas
[i]与cost[i]的差值。判断其是否有充足的油行驶。如果经过前面的站点油还有剩余,则需要加上剩余的油量。
2.不妨将计算出经过每个加油站能剩余的油量,使用数组residue存放。只要求其和sum,如果sum大于等于0,说明到达这里油量是够的,如果小于0,说明油量不够到达。将题目变成求从i开始,sum一直大于等于0,返回 i 。
三、解题代码
示例:
/**
* @param {number[]} gas
* @param {number[]} cost
* @return {number}
*/
var canCompleteCircuit = function(gas, cost) {
const residue = []
//获取每个站的剩余油量
for(let i = 0;i<gas.length;i++){
residue.push(gas[i] - cost[i])
}
let n = residue.length
if(n === 1){
if(residue[0] >= 0) return 0
return -1
}
let start = 0
let end = 1
let sum = residue[0]
let count = 0
//查询和一直大于等于0的开始位置
while(count <= 2*n){
count++
if(sum < 0){
sum = 0
start = end
}
sum = sum+residue[end]
end = (end+1)%n
if(end === start && sum >=0) return start
}
return -1
};
代码解析:代码关键为如何寻找到 i ,使得从 i 开始环绕一周时sum没有小于0的情况,最坏情况是i为最后一个,在环绕一周为次数为2n。在此过程中,如果出现sum小于0的情况,说明前面油量不够,那么重新开始,给start 赋值为 end,从当前位置继续开始,向后求和, end = (end+1)%n实现循环数组的效果,如果end == start且sum >=0;说明已经环绕一周,且油量足够。此时start及就是我们寻找的 i 。
TIP: 可能会有同学问 为什么重新开始计算sum时是 start = end ,而不是 start++。这是因为,sum是时时计算的,从计算sum的开始一定是一个正数,如果后面遇到了sum<0的情况,那一定是后面出现了一个或者多个负数。那么start++无非是抛弃了第一个正数,减少了一个正数,只会整体变小,sum加到相同的地方也必然会再小于0。
换句话说:假设前面的正数,负数相加到第i的时候sum<=0,注意这里sum是第一次<=0;(因为sum是时时判断的),因为前面的开始的数一定是正数,那么说明是一定是加了一个负数,且sum是第一次小于0,所以从前面开始的任何一段都是大于0的(从加sum的第一个数),所以去掉前面任何一段都是都是不可取的。故将start == end 重新开始计算。