【算法】Gas Station(LeetCode134)

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=0n1(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;
    }
}

【算法】Gas Station(LeetCode134)_第1张图片

 

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=0n1(gas[i]cost[i])>=0 就一定能从 start 站开始绕一圈再回到 start 站呢?

反证法证明
假设存在某一个站 j 使得从 start 到站 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,(start1+n)%n],那么就有如下两个条件:

  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=0n1(gas[i]cost[i])>=0
  2. ( 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[start1]cost[start1])+(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[start1]cost[start1])>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[start1]cost[start1])+(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[start2]cost[start2])+(gas[start1]cost[start1])+(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[start2]cost[start2]<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[start1]cost[start1])+(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[start1]cost[start1])+(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[start2]cost[start2]>=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[start2]cost[start2])+(gas[start1]cost[start1])>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[start2]cost[start2])+(gas[start1]cost[start1])>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[start2]cost[start2])+(gas[start1]cost[start1])+(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=0n1(gas[i]cost[i])>=0 ,就可以从 start 站绕一圈回到 start 站。

你可能感兴趣的:(算法,leetcode)