1. 题目介绍
2. 思路
这个题目难点在于对问题的转换,如果画图来看,就比较容易想。这里不是严谨的证明,只是为了记下和理解。
假设有
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]
我们可以绘制这样一张图,绿色部分是可以获得的gas,红色部分是消耗的cost,黑色线条可以看作是从第一个站点开始后剩余gas的变化,这里将这个剩余gas记作。
我们可以推导出两个结论:
-
如果,则无论从哪里出发,最后一定不能走完全程。
这个比较好理解,因为假设走完了,最后的总剩余油量也小于0,不可能存在这种情况。 -
如果有,则以的最小点的后一点开始, 一定是可以得到一条满足题意的路径的。 不太好证明,只好通过变换图像去理解(有种强行说服自己的感觉...)。
我们从不同的起点开始,其实就相当于把原来的黑线,向左向上移动,移动后左边<0部分,向右边拼接。假设我们从第4个点开始,则相当于将上面图表中的第4个点移动到第一位。如下图所示。
黑线是剩余油量,所以每一个点到下一个点的变化趋势是不会变的。
因为黑线的变化趋势不会变,left[i]是最小值,所以在变换后的图像中仍然是最小值的点。(考虑向左向上移动,极小值左侧都是递减的,右侧都是递增的,将左侧的一部分变化量移动到右侧,还是不能得到比原来最小值更小的点,原来的最小值的点还是最小值点)
这里需要注意几点:
(1) 黑线最左边和最右边的点不一定值相等。存在完成后油有更多剩余的情况,本例子只是特例油刚用完了。
(2) 以 i+1 开始只是一种答案,但是题目中说了答案是唯一的,所以数据都是满足这个。
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;
}
};