持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
题目描述
在一条环路上有 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 可为起始索引。
思路分析
其实冲题目中可以提取到的重点就两句话:
- 两个数组之差的总和必须大于等于0,否则不能完成绕行
- 一个站的收益如果小于0,肯定不能作为起点;而连续的多个站也可以等效地看做一个站,如果其累积收益小于0,就跳过,寻找下一个。
双指针
思路:假设剩余气体是last,当前的起始节点为start,当前的结束节点为end。 情况1:如果剩余气体小于0, 那就把start提前一个节点。 情况2:如果剩余气体大于等于0, 那就把end往后走一个节点。
var canCompleteCircuit = function(gas, cost) {
const gassum = gas.reduce((pre, curr) => pre + curr)
const costsum = cost.reduce((pre, curr) => pre + curr)
if(gassum < costsum) return -1
// 之前已经保证是成功的, 下面就是找到开头
const len = gas.length
if(len == 1) return 0
let start = 0, curr = 1 // 任意一个开头都可以
let cursum = gas[start] - cost[start]
while(start !== curr) { // 当 当前指针 走到开始指针就结束
if(cursum >= 0) {
cursum += gas[curr] - cost[curr] // 加上 当前指针
curr = curr == len - 1 ? 0 : curr + 1 // 更新 当前指针
} else { // 如果当前和为负数,说明不能以这个开头,开头指针往前走一步
start = start == 0 ? len - 1 : start - 1 // 先修改开头指针,再添加 添油和耗油的差
cursum += gas[start] - cost[start]
}
}
return start
};
贪心
首先分别计算两个数组的加和, 如果汽油小于消耗,则返回-1.否则肯定有解,具体证明未知
然后计算对应项差的数组,找以数组最后一个元素为结尾的最大子数组和的起始元素。
说的有点抽象,就是找一个数,然后依次加上它之后的数直至结尾,中间的加和不小于0.
使用两个变量分别保存汽车行驶全程耗费的油量和加油站总油量的差run,以及油箱中剩余油量rest
如果rest小于0,说明目前起始点无法行驶到当前加油站,所以更新起始点,并将rest置0.
最后如果run小于0,说明油量不足以支撑全程,返回-1,否则返回起始点。
var canCompleteCircuit = function(gas, cost) {
let greedy = []
let cycleGas = [...gas, ...gas]
let cycleCost = [...cost, ...cost]
for(let i = 0; i < gas.length; i++) {
let curGas = 0
let j = i
while(curGas >= 0 && j - i < gas.length) {
curGas += cycleGas[j]
curGas -= cycleCost[j]
j++
}
if(j - i === gas.length && curGas >= 0) return i
}
return greedy.length > 0 ? greedy[0] : -1
};