leetcode 134 加油站

70 阅读2分钟

1. 题目介绍

题目链接:leetcode.cn/problems/ga…

2. 思路

这个题目难点在于对问题的转换,如果画图来看,就比较容易想。这里不是严谨的证明,只是为了记下和理解。
假设有

gas  = [1,2,3,4,5]
cost = [3,4,5,1,2]

image.png 我们可以绘制这样一张图,绿色部分是可以获得的gas,红色部分是消耗的cost,黑色线条可以看作是从第一个站点开始后剩余gas的变化,这里将这个剩余gas记作leftleft

我们可以推导出两个结论:

  1. 如果i=1ngas<i=1ncost\sum_{i=1}^{n}gas <\sum_{i=1}^{n}cost,则无论从哪里出发,最后一定不能走完全程。
    这个比较好理解,因为假设走完了,最后的总剩余油量也小于0,不可能存在这种情况。

  2. 如果有i=1ngas>=i=1ncost\sum_{i=1}^{n}gas >= \sum_{i=1}^{n}cost,则以leftleft的最小点left[i]left[i]的后一点i+1i+1开始, 一定是可以得到一条满足题意的路径的。 不太好证明,只好通过变换图像去理解(有种强行说服自己的感觉...)。
    我们从不同的起点开始,其实就相当于把原来的黑线,向左向上移动,移动后左边<0部分,向右边拼接。假设我们从第4个点开始,则相当于将上面图表中的第4个点移动到第一位。如下图所示。
    黑线是剩余油量,所以每一个点到下一个点的变化趋势是不会变的。
    因为黑线的变化趋势不会变,left[i]是最小值,所以在变换后的图像中仍然是最小值的点。(考虑向左向上移动,极小值左侧都是递减的,右侧都是递增的,将左侧的一部分变化量移动到右侧,还是不能得到比原来最小值更小的点,原来的最小值的点还是最小值点)
    这里需要注意几点:
    (1) 黑线最左边和最右边的点不一定值相等。存在完成后油有更多剩余的情况,本例子只是特例油刚用完了。
    (2) 以 i+1 开始只是一种答案,但是题目中说了答案是唯一的,所以数据都是满足这个。

image.png

3. 代码

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int n = gas.size();
        int sum = 0;
        int minSum = 0;
        int start = 0;

        for (int i = 0; i < n; ++i)
        {
            sum += gas[i] - cost[i];    // 从i点出发的净消耗
            if (sum < minSum)
            {
                start = i + 1;          // 经过了i点,使sum达到了新低
                minSum = sum;
            }
        }

        if (sum < 0)
        {
            // 总油量小于总消耗,无解
            return -1;
        }

        return start == n ? 0 : start;
    }
};