方法一
public int canCompleteCircuit(int[] gas, int[] cost) {
// 油箱里油的最小值
int min = Integer.MAX_VALUE;
int sum = 0;
for(int i = 0;i<gas.length;i++){
// 每趟剩余的油
int rest = gas[i] - cost[i];
// 油的总和
sum += rest;
// 油的最小差值
min = Math.min(sum,min);
}
// 油的总量小于要消耗的总量,不可以行驶一周
if(sum < 0) return -1;
// 油的最小差值都不为负数,说明从0开始,每趟行驶都有富余的油
if(min >= 0) return 0;
// 从后往前找,看哪个位置富余的油刚好把油的最小差值补上,就从哪里开始
for(int i = gas.length-1;i>=0;i--){
int rest = gas[i] - cost[i];
min += rest;
if(min>=0) return i;
}
return -1;
}
该解法是从全局最优解上考虑的。
情况一:如果gas的总和小于cost总和,那么无论从哪里出发,一定是跑不了一圈的
情况二:rest[i] = gas[i]-cost[i]为一天剩下的油,i从0开始计算累加到最后一站,如果累加没有出现负数,说明从0出发,油就没有断过,那么0就是起点。
情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点gas[i] - cost[i]能这个负数填平,能把这个负数填平的节点就是出发节点。(注意添补时是累加的,比如最小差值min=-6,最后一趟富余的油为3,那么min此时就为-3,再找哪个能填上-3。不是一次性把-6给补上)
方法二
public int canCompleteCircuit(int[] gas, int[] cost) {
// 总剩余油量,若小于0 说明无法跑完全程
int allSum = 0;
// 剩余油量
int rest = 0;
// 开始位置
int start = 0;
for(int i = 0;i<gas.length;i++){
剩余油量的和
rest += gas[i] - cost[i];
总的剩余油量,不可以小于0
allSum += gas[i] - cost[i];
若剩余油量的和小于0,那么之前这段区间都不可以,剩余油量重置为0,起始位置从i+1开始
if(rest<0){
start = i+1;
rest = 0;
}
}
if(allSum < 0) return -1;
return start;
}
此做法为贪心思想,局部最优推出全局最优。若从0到当前i位置的剩余油量累加为负数,那么从0至i区间的所有位置都不可以,起始位置一定在i的后面。