1. 概述
https://leetcode.com/problems/gas-station/
在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i]
升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i]
升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas 和 cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则保证它是唯一的。
2. 思路与代码
思路
从第一个站开始,记录下达到第 i 个站后还剩下的油,如果 > 0,则说明能够到达第 i 个站,如果 < 0,则说明不能到达第 i 个站,需要从下一个 i + 1 站开始再尝试。
最后需要判断,如果 ∑ i = 0 n − 1 ( g a s [ i ] − c o s t [ i ] ) > = 0 \sum_{i=0}^{n-1}(gas[i] - cost[i]) >= 0 ∑i=0n−1(gas[i]−cost[i])>=0 ,则说明能够从 start 站出发,绕一圈回到 start 站。
代码
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int start = 0, total = 0, cur = 0;
for (int i = 0; i < gas.length; i++) {
cur += gas[i] - cost[i];
total += gas[i] - cost[i];
if (cur < 0) {
start = i + 1;
cur = 0;
}
}
return total < 0? -1 : start;
}
}
3. 证明
cur < 0时意味着无法从第 i 站到达第 i + 1 站,需要从 i + 1 站开始重新尝试,这很好理解,但是为什么 ∑ i = 0 n − 1 ( g a s [ i ] − c o s t [ i ] ) > = 0 \sum_{i=0}^{n-1}(gas[i] - cost[i]) >= 0 ∑i=0n−1(gas[i]−cost[i])>=0 就一定能从 start 站开始绕一圈再回到 start 站呢?
反证法证明
假设存在某一个站 j 使得从 start 到站 j 是可行的,但是从第 j 站到第 j + 1 站是不可行的,其中
j
∈
[
(
s
t
a
r
t
+
n
)
%
n
,
(
s
t
a
r
t
−
1
+
n
)
%
n
]
j∈[(start + n) \% n, (start - 1 + n) \% n]
j∈[(start+n)%n,(start−1+n)%n],那么就有如下两个条件:
- ∑ i = 0 n − 1 ( g a s [ i ] − c o s t [ i ] ) > = 0 \sum_{i=0}^{n-1}(gas[i] - cost[i]) >= 0 ∑i=0n−1(gas[i]−cost[i])>=0
- ( g a s [ s t a r t ] − c o s t [ s t a r t ] ) + ( g a s [ s t a r t + 1 ] − c o s t [ s t a r t + 1 ] ) + . . . + ( g a s [ j ] − c o s t [ j ] ) < 0 (gas[start] - cost[start]) + (gas[start + 1] - cost[start + 1]) + ... + (gas[j] - cost[j]) < 0 (gas[start]−cost[start])+(gas[start+1]−cost[start+1])+...+(gas[j]−cost[j])<0
那么就可以得出条件3
( g a s [ j + 1 ] − c o s t [ j + 1 ] ) + ( g a s [ j + 2 ] − c o s t [ j + 2 ] ) + . . . + ( g a s [ s t a r t ] − c o s t [ s t a r t ] ) > 0 (gas[j + 1] - cost[j + 1]) + (gas[j + 2] - cost[j + 2]) + ... + (gas[start] - cost[start]) > 0 (gas[j+1]−cost[j+1])+(gas[j+2]−cost[j+2])+...+(gas[start]−cost[start])>0
如果
j = start - 1
因为是从 start 站出发的,说明不能从 start - 1 站到达 start 站,而与条件3是相矛盾的,因此 j 不能等于 start - 1。
j = start - 2
已知不能从 start - 1 站到达 start 站,因此有
g a s [ s t a r t ] − c o s t [ s t a r t ] < 0 gas[start] - cost[start] < 0 gas[start]−cost[start]<0
并且有条件3:
( g a s [ s t a r t − 1 ] − c o s t [ s t a r t − 1 ] ) + ( g a s [ s t a r t ] − c o s t [ s t a r t ] ) > 0 (gas[start - 1] - cost[start - 1]) + (gas[start] - cost[start]) > 0 (gas[start−1]−cost[start−1])+(gas[start]−cost[start])>0
那么就有
( g a s [ s t a r t − 1 ] − c o s t [ s t a r t − 1 ] ) > 0 (gas[start - 1] - cost[start - 1]) > 0 (gas[start−1]−cost[start−1])>0
也就是说,能够从 start - 2 站开始到达 start - 1 站,而且 ( g a s [ s t a r t − 1 ] − c o s t [ s t a r t − 1 ] ) + ( g a s [ s t a r t ] − c o s t [ s t a r t ] ) > 0 (gas[start - 1] - cost[start - 1]) + (gas[start] - cost[start]) > 0 (gas[start−1]−cost[start−1])+(gas[start]−cost[start])>0,那么从 start - 2 站开始到达了 start - 1 站,可以继续从 start - 1 站到达 start 站,因为剩下的油是够的。
产生了矛盾,因此 j 不能等于 start - 2。
j = start - 3
已知不能从 start - 1 站到达 start 站,因此有
g a s [ s t a r t ] − c o s t [ s t a r t ] < 0 gas[start] - cost[start] < 0 gas[start]−cost[start]<0
并且有条件3:
( g a s [ s t a r t − 2 ] − c o s t [ s t a r t − 2 ] ) + ( g a s [ s t a r t − 1 ] − c o s t [ s t a r t − 1 ] ) + ( g a s [ s t a r t ] − c o s t [ s t a r t ] ) > 0 (gas[start - 2] - cost[start - 2]) + (gas[start - 1] - cost[start - 1]) + (gas[start] - cost[start]) > 0 (gas[start−2]−cost[start−2])+(gas[start−1]−cost[start−1])+(gas[start]−cost[start])>0
如果 g a s [ s t a r t − 2 ] − c o s t [ s t a r t − 2 ] < 0 gas[start - 2] - cost[start - 2] < 0 gas[start−2]−cost[start−2]<0,那么就有 ( g a s [ s t a r t − 1 ] − c o s t [ s t a r t − 1 ] ) + ( g a s [ s t a r t ] − c o s t [ s t a r t ] ) > 0 (gas[start - 1] - cost[start - 1]) + (gas[start] - cost[start]) > 0 (gas[start−1]−cost[start−1])+(gas[start]−cost[start])>0
而根据上面的证明, ( g a s [ s t a r t − 1 ] − c o s t [ s t a r t − 1 ] ) + ( g a s [ s t a r t ] − c o s t [ s t a r t ] ) > 0 (gas[start - 1] - cost[start - 1]) + (gas[start] - cost[start]) > 0 (gas[start−1]−cost[start−1])+(gas[start]−cost[start])>0 是会产生矛盾的,因此必然有 g a s [ s t a r t − 2 ] − c o s t [ s t a r t − 2 ] > = 0 gas[start - 2] - cost[start - 2] >= 0 gas[start−2]−cost[start−2]>=0
也即,从 start - 3 站开始能够到达 start - 2 站。
因为
g
a
s
[
s
t
a
r
t
]
−
c
o
s
t
[
s
t
a
r
t
]
<
0
gas[start] - cost[start] < 0
gas[start]−cost[start]<0,所以必然有
( g a s [ s t a r t − 2 ] − c o s t [ s t a r t − 2 ] ) + ( g a s [ s t a r t − 1 ] − c o s t [ s t a r t − 1 ] ) > 0 (gas[start - 2] - cost[start - 2]) + (gas[start - 1] - cost[start - 1]) > 0 (gas[start−2]−cost[start−2])+(gas[start−1]−cost[start−1])>0
那么,根据上面的证明,能从 start - 3 站开始到达 start - 2 站,并且在到达了 start - 2 站后有 ( g a s [ s t a r t − 2 ] − c o s t [ s t a r t − 2 ] ) + ( g a s [ s t a r t − 1 ] − c o s t [ s t a r t − 1 ] ) > 0 (gas[start - 2] - cost[start - 2]) + (gas[start - 1] - cost[start - 1]) > 0 (gas[start−2]−cost[start−2])+(gas[start−1]−cost[start−1])>0,也就是油足够从 start - 2 站继续到达 start - 1站。
在到达了 start - 1 站后,因为
(
g
a
s
[
s
t
a
r
t
−
2
]
−
c
o
s
t
[
s
t
a
r
t
−
2
]
)
+
(
g
a
s
[
s
t
a
r
t
−
1
]
−
c
o
s
t
[
s
t
a
r
t
−
1
]
)
+
(
g
a
s
[
s
t
a
r
t
]
−
c
o
s
t
[
s
t
a
r
t
]
)
>
0
(gas[start - 2] - cost[start - 2]) + (gas[start - 1] - cost[start - 1]) + (gas[start] - cost[start]) > 0
(gas[start−2]−cost[start−2])+(gas[start−1]−cost[start−1])+(gas[start]−cost[start])>0 ,那么剩下的油可以继续从 start - 1 站到达 start 站。
因此就出现了矛盾,因此 j 不能等于 start - 3
同理可证
同理,可以证明 j 不能取其他的值,也即 j 是不存在的,那么即说明,只要 ∑ i = 0 n − 1 ( g a s [ i ] − c o s t [ i ] ) > = 0 \sum_{i=0}^{n-1}(gas[i] - cost[i]) >= 0 ∑i=0n−1(gas[i]−cost[i])>=0 ,就可以从 start 站绕一圈回到 start 站。