- 暴力 + 剪枝
最容易想到的暴力解法就是挨个遍历,假设下标 i 是出发时加油站的编号,变量 sum 存储当前剩余油量,从下标 j = i 开始维护更新 sum 值
当 sum 小于 0 时,说明从 i 出发不能完成环路行驶,跳出循环从下一个下标开始sum += (gas[j % len] - cost[j % len]);
这里有几点剪枝操作:
1、总油量大于等于总耗油量:即 gas 数组中的总和大于等于 cost 数组中的总和,才可能完成环路行驶,否则直接返回 -1
2、若只有一个加油站,需通过 gas 和 cost 中数值的大小比较判断能否完成//sum(int[] nums) 是自定义方法 if (sum(gas) < sum(cost)) return -1;
3、出发点的油量大于到下一个点的耗油量//len = gas.length if(len < 2) return gas[0] >= cost[0] ? 0 : -1;
总代码:gas[i] > cost[i]
public static int canCompleteCircuit(int[] gas, int[] cost) { int len = gas.length; if(len < 2) return gas[0] >= cost[0] ? 0 : -1; if (sum(gas) < sum(cost)) return -1; for (int i = 0; i < len; i++) { if (gas[i] > cost[i]){ int sum = 0; //从下标 i 开始 for (int j = i; j <= i + len; j++) { //注意下标值 sum += (gas[j % len] - cost[j % len]); if (sum < 0) break; } if (sum >= 0) return i; } } return -1; } public static int sum(int[] nums) { int sum = 0; for (int i = 0; i < nums.length; i++) { sum += nums[i]; } return sum; }
- 填坑思想
看到一个很有参考价值的想法:
亏空最严重的一个点必须放在最后一步走,等着前面剩余的救助
这个想法是在找 gas[i] - cost[i] 总和的最低点 minIndex,这个最低点就是亏空最严重的地方,那么将这个点放在最后去经过就是最安全的,即将 minIndex 的下一个点作为出发点
这里要注意一个判断条件:出发点的油量大于到下一个点的耗油量
代码如下:
public static int canCompleteCircuit(int[] gas, int[] cost) {
int len = gas.length;
int sum = 0;
int min = Integer.MAX_VALUE, minIndex = 0;
for (int i = 0; i < len; i++) {
sum += gas[i] - cost[i];
if (sum < min && gas[(i + 1) % len] > cost[(i + 1) % len]) {
min = sum;
minIndex = i;
}
}
return sum < 0 ? -1 : (minIndex + 1) % len;
}