• 【LeetCode-贪心】加油站


    题目描述

    在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

    你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

    如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

    说明:

    • 如果题目有解,该答案即为唯一答案。
    • 输入数组均为非空数组,且长度相同。
    • 输入数组中的元素均为非负数。

    示例:

    输入: 
    gas  = [1,2,3,4,5]
    cost = [3,4,5,1,2]
    
    输出: 3
    
    解释:
    从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
    开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
    开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
    开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
    开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
    开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
    因此,3 可为起始索引。
    

    题目链接: https://leetcode-cn.com/problems/gas-station/

    思路1

    假设起始点为 i,则起始点的油量 gas[i] 一定是大于等于消耗 cost[i] 的,所以我们先找到所有可能为起始点的位置。
    记录当前油量 curGas,对于每一个起始点:

    • curGas = curGas + gas[i] - cost[i];
    • 如果 curGas 小于 0,则说明该起始点不符合要求;尝试下一个起始点;否则返回起始点;

    如果所有的起始点都不行,则返回 -1.

    代码如下:

    class Solution {
    public:
        int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
            vector<int> starts;
            int n = gas.size();
            for(int i=0; i<n; i++){
                if(gas[i]>=cost[i]) starts.push_back(i); // 找到所有可能的起始点
            }
    
            for(int i=0; i<starts.size(); i++){ // 尝试每一个可能的起始点
                int departion = starts[i];
                int curPos = starts[i];
                int curGas = gas[curPos] - cost[curPos];
                curPos = (curPos+1)%n;
                bool flag = true;
                while((curPos)%n!=departion){
                    curGas += gas[curPos];
                    curGas -= cost[curPos];
                    if(curGas<0){
                        flag = false;
                        break;
                    }
                    curPos = (curPos+1)%n;
                }
                if(flag) return departion;
            }
            return -1;
        }
    };
    

    思路2

    使用两个变量 totalGas 记录总的油量剩余,如果跑一边 totalGas<0,则说明无解;使用 curGas 表示从起始点 start 出发到当前位置 i 剩余的油量。如果 curGas<0,则说明从之前的起始点到当前位置不可行,需要寻找新的起始点,新的起始点设为 i+1.

    这里有一个问题就是为什么新的起始点要设置为 i+1,而不设置为 [start, i] 之间的点,假设 j ∈ [start, i],则从 j 出发到 i 的 curGas 也会是小于 0 的。

    当遍历结束时,如果 totalGas>0,则说明有解,返回记录的起始点;否则返回 -1.

    代码如下:

    class Solution {
    public:
        int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
            int totalGas = 0;
            int curGas = 0;
            int start = 0;
            for(int i=0; i<gas.size(); i++){
                int rest = gas[i] - cost[i];
                totalGas += rest;
                curGas += rest;
                if(curGas<0){
                    curGas = 0;
                    start = i+1;
                }
            }
            return totalGas<0? -1:start;
        }
    };
    
    • 时间复杂度:O(n)
    • 空间复杂度:O(1)
  • 相关阅读:
    洛谷P3258 [JLOI2014]松鼠的新家
    洛谷P3128 [USACO15DEC]最大流Max Flow
    Bzoj1651: [Usaco2006 Feb]Stall Reservations 专用牛棚
    2017-9-26 NOIP模拟赛
    洛谷P1441 砝码称重
    洛谷P1275 魔板
    洛谷P2037 电话号码
    2014-11-3 NOIP模拟赛2
    洛谷P3102 [USACO14FEB]秘密代码Secret Code
    洛谷P3070 [USACO13JAN]岛游记Island Travels
  • 原文地址:https://www.cnblogs.com/flix/p/13276146.html
Copyright © 2020-2023  润新知