题目
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.
由于题目说了如果有解,一定只有一个,因此与经典的“求数组连续子序列的最大和”问题思路一致,找到这样的子序列后,子序列的起始节点即为问题的解。
由于这里是个环形数组,就需要遍历两遍才能涵盖所有情况。
需要注意的时,虽然是遍历两遍,但是如果存在解的话,起始节点在第一轮遍历时就应该确定了。如果转到第二圈还没确定起始节点,那说明gas总是不够用,其实就是无解。
解法1
public class GasStation {
public int canCompleteCircuit(int[] gas, int[] cost) {
int N = gas.length;
int seqStart = 0;
int max = 0;
for (int i = 0; i < 2 * N; ++i) {
int index = i % N;
int remain = gas[index] - cost[index];
if (max + remain < remain) {
max = remain;
seqStart = i;
} else {
max = max + remain;
}
}
if (seqStart >= N) {
return -1;
}
return seqStart;
}
}
分析2
要判断是否有解,只需要累加gas数组和cost数组,如果gas数组和不小于cost数组和,那么就一定有解。
在一定有解的情况下,可以充分利用题目给出的“如果有解,就一定只有一个”的条件。我们可以借鉴分析1中最大子序列和的思路进行反向思考,找到最缺油的那个点,那么最缺油的那个点的下一个节点就应该是起始节点了。
解法如下,只需要遍历一遍即可。
解法2
public class GasStation {
public int canCompleteCircuit(int[] gas, int[] cost) {
int ret = 0;
int N = gas.length;
int min = Integer.MAX_VALUE;
int remain = 0;
for (int i = 0; i < N; ++i) {
remain += gas[i] - cost[i];
if (remain < min) {
min = remain;
ret = i + 1;
}
}
if (remain < 0) {
return -1;
}
return ret % N;
}
}