LeetCode(贪心)-134-加油站

示例:

由于每次经过一个加油站都会得到油的补充,同时开往下一站还会消耗一定数量的油。那么不妨计算每个加油站的净增油量。

以gas = [1, 2, 3, 4, 5], cost = [3, 4, 5, 1, 2]为例——

我们可以计算出每一个站点的净增油量,比如站点1,我们获得单位1的油量,同时又消耗单位3的油量。那么我们的净增油量就为-2个单位的油量。同理,我们可以计算出每个站点的净增油量。

在上述例子中,每个站点净增油量就为[-2, -2, -2, 3, 3]

那么可以预见的是,如果我们想要从某点出发并环绕一圈回到出发点的话,那么我们的净增油量肯定是大于或者等于0的。

并且如果我们的净增油量大于或者等于0,那么肯定也是可以环绕一圈的。因为我们无论从任何位置出发,其所净增的油量总是能支撑我们回到出发点,如果净增油量小于0,那么肯定在中途某个点就必须停下来了。但是我们又不能从任意位置出发,比如上述例子的第二号加油站,净增油量为负数,不足以支撑我们到达下一个站点。

那么这样或许就有一个思路了—— 

如果在净增油量总和都大于0的情况下,如果我们想要跑完一圈,那么我们就是希望不会出现当前净增油量和为负数的情况。

如果已经舍弃了所有为净增油量和为负数的情况,那么剩下的便是结果。

先给出具体代码:

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int startIndex = 0;
        int curSum = 0, TotalSum = 0;
        //局部和&&全局和
        for (int i = 0; i < cost.length; i++) {
            //计算经过每个站点的净剩余油量总和
            TotalSum += gas[i] - cost[i];
        }
        //如果净剩余油量总和小于0就是不可能环绕一圈的
        if(TotalSum < 0)
            return -1;
        for (int i = 0; i < cost.length; i++) {
            //局部和
            //如果局部和小于0,说明从startIndex的位置出发是不可能环绕一圈的
            curSum += gas[i] - cost[i];
            //出现curSum小于0的位置就重置curSum,并且将starIndex更新为下一个点
            //此时下一个点将成为可能的答案
            //以此循环直到循环结束,那么最后一个startIndex更新的值就是答案
            if(curSum < 0){
                startIndex = i + 1;
                curSum = 0;
            }
        }
        return startIndex;
    }
}

我们从i = 0开始遍历,依次累加curSum,表示当前各站点净增油量总和。当发现累加上当前点后,curSum < 0便直接从下一点开始。

为什么中间的各点可以不遍历呢?万一某点开始curSum大于0呢?

这是不可能的啊——

反证法:

设起始位置为x,使得curSum小于0的点为y。那么在[x, y]区间,如果存在一点r,使得curSum--->[r, y]大于0,那么按照我们的代码逻辑,此点r一定是当取得curSum--->[x, r - 1]小于0后startIndex更新取得的。那么这样的话就不存在从x遍历到y的过程了,因为当我们从x遍历到r - 1的时候就已经更新了。

这与我们假设的过程相矛盾,所以[x, y]中不存在某点使得从当前点开始直到y,curSum大于0。

直接证明:

我们的前提是一定存在从x到y的连续过程。

那么设连续和为Sum = a(x) + a(x + 1) + a(x + 2) + ... + a(y),取其中任意一点x + n开始(n < y - x)我们需要证明的是无论从任意一点(x + n)开始,直到点y,连续和必定小于0。

因为在代码逻辑中,当我们遇到curSum < 0后便结束当前遍历,并从下一点重新开始。那么在我们的前提下,点(x + n)之前的部分连续和一定是大于0的,因为如果小于0,从x开始的遍历便中断了,这不符合我们定义的大前提!

所以点(x + n)之前累加上来的值一定大于0,另其为sum1(sum1 > 0),另从点(x + n)开始直到点y的连续和为sum2。因为总和小于0,即sum1 + sum2 < 0,又因为sum1大于0,所以sum2必定小于0至此我们证明了从任意一定(x + n)开始(n < y - x),直到点y,连续和必定小于0。从而证明万一从某点开始curSum大于0的猜测是不成立的!

所以我们直接舍弃遍历途中中间的各点

那么当我们遍历到数组末尾,最后一次更新的startIndex就是起始位置了。

因为我们的大前提是净增油量总和大于或等于0,将startIndex前面的部分和定义为sum1, 其后包括其本身定义为sum2.那么sum1必定小于0,sum2必定大于0,并且sum2必定大于sum1的绝对值。所以从startIndex可以环绕数组一圈。

不知道这样讲述是否正确,思路参考《代码随想录》卡尔老师,加上了一点自己的理解,此作为对自己对学习贪心一段时间过后的复习与总结。

贪心算法,得这么加油才能跑完全程!LeetCode :134.加油站_哔哩哔哩_bilibili

代码随想录 (programmercarl.com)

再次感谢卡尔老师的讲解!

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值