首页 > 其他分享 >leet code 134.加油站

leet code 134.加油站

时间:2023-10-14 16:04:51浏览次数:40  
标签:leet code 油量 min int sum gas cost 134

134.加油站

题目解析

由题目中示例一,存在两个数组。

  • 一个是 gas = {1, 2, 3, 4, 5} 代表了加油站
  • 一个是 cost = {3, 4, 5, 1, 2} 代表了消耗的汽油
  • 需要求证的是,从 索引i出发是否能够绕行一周回到索引i的位置
  • ex:比如从gas[0] 出发,能够获取的 油量 = 1 想要开往下一个加油站的话需要消耗 油量 = 3
  • 因此,不能够从 第 0 号加油站出发
  • 由此可以得出结论,当 cost[k] > gas[k] 的时候,是不能够从第 k 号加油站出发的
  • 所以,唯一的解必定出现在 gas[k] >= cost[k]
  • 那么如果按照题目中给出的计算方法一一计算的话,该种方法可行。
  • 但是 时间复杂度没有办法保证
  • 果不其然,超时了

show code : 超时了

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;
        List<Integer> list = new ArrayList<>();

        for(int i = 0;i < n;i++) {
            if(gas[i] >= cost[i]) {
                list.add(i);
            }
        }

        if(list.size() == 1) {
            return list.get(0);
        }

        for(int i : list) {
            int sz = n;
            int localGas = 0;
            // 这个时候从 i 出发判断能够回到 索引 i
            int startIdx = i;
            while(sz > 0) {

                localGas += gas[startIdx];
                localGas -= cost[startIdx];

                if(localGas < 0) {
                    // 没有办法到达下一个加油站
                    break;
                }
                startIdx++;
                if(startIdx == n) {
                    startIdx = 0;
                }
                sz--;
            }
            if(startIdx == i) {
                return i;
            }
        }

        return -1;
    }
}

  • 超时的主要原因在于,对于每一个符合条件的出发点,都进行计算验证判断其是否是唯一解。
  • 再加上数据量级达到了leet code 134.加油站_最小值,所以超时了。

再接再厉

  • 再次仔细观察题目中的用例
  • 通过区分 示例1 和 示例2
  • 可以发现,当 sum_gas (油的总量) < cost_gas (消耗的总量) 的时候,很显然是无法按照顺序 “环路一周的”
  • 再进行思考,当 sum_gas >= cost_gas 的时候有什么特征可以利用吗?
  • 想不出来,查看一下题目标签。
  • 标签是 贪心+数组 如何运用贪心思维来解决?

  • 想不出来,学习其它解。
  • 求数组 gascost 的差前缀和,即 gas[i] - cost[i]
  • 如果最终求得的前缀和sum < 0很显然无法 “环路一周”
  • sum >= 0的时候,前缀和最小的下一位就是 “唯一解”
  • 为什么?
  • 求得差前缀和数组之后,记差数组前缀和最小值min = diff[j]
  • 结合题意 min 一定是小于 0 的,因为如果 min 大于 0 意味着从任何位置都可以 “环路一周”,就不存在唯一解了
  • 为什么 min 对应索引位置的下一个位置是唯一解?
  • 倒推
  • 从唯一解的位置出发最终再回到唯一解的位置的时候,油量 >= 0
  • 从其它位置出发的时候无法回到出发位置
  • 已知:从唯一解出发的时候,油量收益肯定不是负的。
  • 从收益角度看,在 min 位置的时候,收益最小,从min 下一个位置开始收益开始为正

show code

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;
        // 记录两个数组的差前缀和.
        int sum = 0;
        // 初始化最小值是 0.
        int min = 0;
        // 记录最小值对应的下一个索引位置.
        int idx = 0;
        for(int i = 0;i < n;i++) {
            sum += gas[i] - cost[i];
            if(sum < min) {
                min = sum;
                idx = i + 1;
            }
        }
        return sum < 0?-1:idx;
    }
}

一个更好的思路

  • 从一个位置开始遍历
  • 判断是否能够到达下一个位置
  • 如果能,证明油量可能有剩余,那么记录下剩余的油量
  • 如果不能,证明油量不够。记录下缺少的油量
  • 这个时候记录一下下一个位置,判断是否能够 “环路一种”

show code

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        // 记录剩余油
        int leftGas = 0;
        // 当前点不可达,记录缺少的油
        int lackGas = 0;
        // 重试的起点——前一个位置不可达的点
        int newIdx = 0;
        int n = gas.length;
        for(int i = 0;i < n;i++) {
            // 计算到下一个点,剩多少油
            leftGas += gas[i] - cost[i];
            if(leftGas < 0) {
                // 无法达到下一个点,记录缺少的油量
                lackGas += -leftGas;
                // 剩余油量重置为 0,从下一个点开始重试出发
                newIdx = i + 1;
                leftGas = 0;
            }
        }

        // 遍历完成,查看剩余油量是否能够填补空缺,如果能,则找到了唯一解 即 newIdx
        return leftGas >= lackGas?newIdx : -1;
    }
}

标签:leet,code,油量,min,int,sum,gas,cost,134
From: https://blog.51cto.com/u_16079703/7861988

相关文章

  • Codeforces Round 748 (Div. 3) B. Make it Divisible by 25
    给一个正整数\(n\),在一步操作中可以移除\(n\)中的一个。当\(n\)只剩下一位时将不能再操作,如果过程中产生了前导\(0\),则会被自动移除且不耗费操作次数。询问最少需要多少次操作可以使得\(n\)被\(25\)整除。显然一个正整数\(x\)若可以被\(25\)整除,只需要考虑最后......
  • Educational Codeforces Round 116 (Rated for Div. 2) A. AB Balance
    给一个长为\(n\)的字符串\(s\),只包含\(0\)\(1\)两种字符。定义\(AB(s)\)是\(s\)中出现的\(01\)子串个数,\(BA(s)\)是\(s\)中出现的\(10\)子串个数。在一步操作中,可以选择一个字符进行异或。询问最小的操作次数使得\(AB(s)=BA(s)\)。显然连续的\(11\)或连......
  • ubuntu安装vscode
    本文章过程在ubuntu20.04版本16.04下安装非常顺利官网:https://code.visualstudio.com/Download#下载链接格式https://update.code.visualstudio.com/{version}/linux-deb-x64/stable#下载版本:1.57.0wgethttps://update.code.visualstudio.com/1.57.0/linux-deb-x64/s......
  • Codeforces Round 903 (Div. 3) E. Block Sequence(DP)
    CodeforcesRound903(Div.3)E.BlockSequence思路:设dp[i]为当i~n为完美的最少删除次数dp[n]=1,dp[n+1]=0;从后至前对于dp[i]更新若直接删除当前点,则为dp[i+1]+1若不删除则为min(dp[i+a[i]+1],dp[i]);i+a[i]+1为a[i]不能覆盖的位置#defineintlonglong#define......
  • AtCoder Beginner Contest 321 C-321-like Searcher
    可以观察到0-9的所有子集都能恰组成一个满足题目条件的数字,所以共有1022个数{除空集和0}方法就是二元枚举,找出所有数然后排序。#include<iostream>#include<cstdio>#include<vector>#include<algorithm>usingnamespacestd;usingll=longlong;vector<ll>v;sig......
  • Atcoder beginner constest319 Minimum Width
    因为要求窗口的最小宽度,当宽度为w时满足条件,那么宽度为w+1时也满足条件,有此可见是有单调性的,那么可以用二分搜的方法,且此题目一定有解。因为M最大为2乘以10的5次方,Li最大为10的9次方,所以宽度最大为2乘以10的14次方,单词每次间隔1,所以这里设成10的17次方。之后就是套二分模板解暴力......
  • 提交代码遇到not allowed to push code git info detecting host provider for 网址解
    查看git出错信息>gitpush-uoriginandroidinfo:detectinghostproviderfor'https://AA.com/'...warning:-----------------SECURITYWARNING----------------warning:|TLScertificateverificationhasbeendisabled!|warning:---------------......
  • Codeforces Round 903 (Div. 3)
    D题被hack了哭了第一题简单的只用把字符串重复的同时尝试匹配,然后判断就好了,只是需要一点代码能力第二题,也很简单最多剪断3次,就先从小到大排序,然后用最小的,看看大的是他的几倍,如果不是几倍的关系就不可能完成,如果是就算要几次就好了第三题,也很简单,很明显,对于一个格子,在它旋转9......
  • #yyds干货盘点# LeetCode程序员面试金典:用最少数量的箭引爆气球
    1.简述:有一些球形气球贴在一堵用XY平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i]=[xstart,xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切y坐标。一支弓箭可以沿着x轴从不同点 完全垂直 地射出。在坐标 x 处射出一......
  • Codeforces Round 674 (Div. 3) B. Symmetric Matrix
    有\(n\)块\(2\times2\)的瓷砖,瓷砖上的每个方格包含一个数字,每种瓷砖都有无数种。现在需要用所给瓷砖构造一个\(m\timesm\)的方形矩阵\(a\)满足:每块瓷砖都在方形矩阵内瓷砖之间不能存在覆盖\(a_{i,j}=a_{j,i}\)。输出是否存在这种构造。一:显然合法的\(m\)......