There are N gas stations along a circular route, where the amount of gas at station i is gas[i].
You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1).
You begin the journey with an empty tank at one of the gas stations.
Return the starting gas station's index if you can travel around the circuit once, otherwise return -1.
Note:
The solution is guaranteed to be unique.
思路:
这题要想清楚不容易,尽管想清楚后代码写起来很简单。
I. 显然当gas[i]<cost[i]时,i不能作为起点。
II. 当对所有加油站求和:sum(gas[i] - cost[i]) <0时,无法环绕一圈。反之,则一定能环绕一圈。
问题是如果可以环绕一圈,如何找起点?
性质1. 对于任意一个加油站i,假如从i出发可以环绕一圈,则i一定可以到达任何一个加油站。显而易见。
性质2. 如果这样的i是唯一的,则必然不存在j!=i, 从j出发可以到达i。
反证法:如果存在这样的j,则必然存在j->i->i的路径,而这个路径会覆盖j->j一周的路径。那么j也将是一个符合条件的起点。与唯一解的限制条件矛盾。
性质3. 假如i是最后的解,则由1可知,从0 ~ i-1出发无法达到i。而从i出发可以到达i+1 ~ n-1。
结合以上三条性质,得出解决的思路:
0. 如果对所有加油站的sum(gas[i] - cost[i])<0,则无解。否则进入1。
1. 从0开始计算sum(gas[i] - cost[i]),当遇到i1使sum<0时,说明从0出发无法到达i1+1。根据性质1,0不是起始点。而由于从0出发已经到达了1 ~ i1。根据性质2,1 ~ i1一定不是正确的起始点。此时i1+1为起始点的候选。
2. 将sum清0,并从i1+1出发,假如又遇到i2使sum(gas[i] - cost[i]) < 0 时,说明i1+1出发无法绕一圈,根据性质1,排除i1+1。又因为i1+2 ~ i2都能从i1+1出发到达,。根据性质2,它们也必然不是起始点。此时i2+1为起始点的候选。
3. 以此类推,直到遇到ik+1,使从ik+1出发可以到达ik+2 ~ n-1。
其中步骤0可以合并到1~3的扫描中,一个pass来得到解。
class Solution {
public:
int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
int start = 0, netGasSum = 0, curGasSum = 0;
for(int i=0; i<cost.size(); i++) {
netGasSum += gas[i] - cost[i];
curGasSum += gas[i] - cost[i];
if(curGasSum<0) {
start = i+1;
curGasSum = 0;
}
}
if(netGasSum < 0) return -1;
return start;
}
};Lexi的解释是这样的:
这个题要用反证法来理解。算法:
- 从i开始,j是当前station的指针,sum += gas[j] – cost[j] (从j站加了油,再算上从i开始走到j剩的油,走到j+1站还能剩下多少油)
- 如果sum < 0,说明从i开始是不行的。那能不能从i+1到j的某个位置开始呢?假设能从k (i <k<=j)走,那么i..j < 0,若k..j >=0,说明i..k – 1更是<0,那从k-1处就早该断开了,根本轮不到j。
- 所以一旦sum<0,i就赋成j + 1,sum归零。
- 最后total表示能不能走一圈。
- 这个题算法简单,写起来真是够呛。对数组一快一慢双指针的理解还是不行。注意千万不能出现while (i < 0) { i++, A[i]}这种先++然后取值的情况,必须越界。
public int canCompleteCircuit(int[] gas, int[] cost) {
int i = 0, j = 0;
int sum = 0;
int total = 0;
while (j < gas.length) {
int diff = gas[j] - cost[j];
if (sum + diff < 0) {
i = j + 1;
sum = 0;
} else {
sum += diff;
}
j++;
total += diff;
}
return total >= 0 ? i : -1;
}
本文深入探讨了如何通过反证法和性质分析,解决汽油与成本最小化循环路线的问题。详细解释了算法逻辑,包括从数组元素的累加和判断能否完成循环,最终确定起始点的策略。
336

被折叠的 条评论
为什么被折叠?



