力扣第134题 加油站 c++ 暴力 + 贪心

题目

134. 加油站

中等

相关标签

贪心 数组

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

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

给定两个整数数组 gascost ,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

示例 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 可为起始索引。

示例 2:

复制代码
输入: gas = [2,3,4], cost = [3,4,3]
输出: -1
解释:
你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。
我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油
开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油
开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油
你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。
因此,无论怎样,你都不可能绕环路行驶一周。

提示:

  • gas.length == n
  • cost.length == n
  • 1 <= n <= 105
  • 0 <= gas[i], cost[i] <= 104

思路和解题方法 一(暴力)

  • 目标是判断给定的汽油站能否构成一个环路,使得可以从某个站点出发,顺时针往前绕一圈返回该站点。每个站点有两个属性:gas[i] 表示在该站点加油可获得的油量,cost[i] 表示从该站点到下一个站点需要消耗的油量。
  • 为了判断是否可以行驶一圈,我们可以模拟一遍整个过程。假设从第 i 个站点出发,开始时剩余油量为 gas[i]−cost[i],依次到达第 i+1,i+2,...,n−1,0,1,...,i−1 个站点,每经过一个站点,就用消耗的油量减去加入的油量,同时记录当前的剩余油量。如果最后回到了起点且剩余油量不小于 0,则说明可以完成一次环形行驶。

复杂度

时间复杂度:

O(n*n)

时间复杂度: O(n*n),n 是站点数,因为每个站点都可能做一次循环检查。

空间复杂度

O(1)

空间复杂度: O(1),只需要常数个变量记录当前状态即可。

c++ 代码 一 (暴力)

cpp 复制代码
class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        for (int i = 0; i < cost.size(); i++) {   // 对于每一个点,以它为起点做一次循环检查
            int rest = gas[i] - cost[i];          // 记录当前点的剩余油量
            int index = (i + 1) % cost.size();    // 初始化index指向下一个点

            while (rest > 0 && index != i) {      // 如果还有油且没有回到起点,就继续往前走
                rest += gas[index] - cost[index]; // 更新剩余油量
                index = (index + 1) % cost.size();// 更新下一个点
            }

            if (rest >= 0 && index == i) {        // 如果油足够到达终点并回到起点了,就返回起点
                return i;
            }
        }

        return -1;                                // 否则返回-1
    }
};

思路和解题方法 二(贪心)

  • 当我们遍历每个站点时,我们首先更新curSum和totalSum。curSum是从起始位置到当前位置的累加剩余油量,它等于上一个位置的curSum加上当前站点的剩余油量(gas[i] - cost[i])。totalSum是所有站点的累加剩余油量,它等于上一个位置的totalSum加上当前站点的剩余油量(gas[i] - cost[i])。
  • 接下来,我们判断curSum是否小于0,如果小于0,说明从起始位置到达当前位置的路径不可行。因为如果从起始位置开始,累加剩余油量一直小于0,那么无论从哪个位置出发都无法完成一次环形行驶。所以,我们将起始位置更新为当前位置的下一个位置(i + 1),并且重置curSum为0,相当于重新开始计算累加剩余油量。
  • 最后,我们在遍历结束后检查totalSum是否小于0。如果totalSum小于0,说明所有站点的累加剩余油量都是负数,即无法完成一次环形行驶,返回-1。否则,我们返回起始位置start,因为凡是能够完成一次环形行驶的情况下,start位置一定是符合条件的。

复杂度

时间复杂度:

O(n)

时间复杂度: O(n),其中n是站点数。遍历一次所有站点进行累计操作。

空间复杂度

O(1)

空间复杂度: O(1),只需要常数个变量记录当前状态。

c++ 代码 二 (贪心)

cpp 复制代码
class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int curSum = 0;      // 当前累加剩余油量
        int totalSum = 0;    // 总累加剩余油量
        int start = 0;       // 起始位置

        for (int i = 0; i < gas.size(); i++) {
            curSum += gas[i] - cost[i];    // 更新当前累加剩余油量
            totalSum += gas[i] - cost[i];  // 更新总累加剩余油量

            if (curSum < 0) {   // 当前累加剩余油量小于0,说明从起始位置到达当前位置的路径不可行
                start = i + 1;  // 更新起始位置为当前位置的下一个位置
                curSum = 0;     // 重置当前累加剩余油量为0
            }
        }

        if (totalSum < 0) return -1;   // 总累加剩余油量小于0,说明无法完成一次环形行驶,返回-1
        return start;                  // 返回起始位置
    }
};

对于这里的解释

cpp 复制代码
            curSum += gas[i] - cost[i];    // 更新当前累加剩余油量
            totalSum += gas[i] - cost[i];  // 更新总累加剩余油量

            if (curSum < 0) {   // 当前累加剩余油量小于0,说明从起始位置到达当前位置的路径不可行
                start = i + 1;  // 更新起始位置为当前位置的下一个位置
                curSum = 0;     // 重置当前累加剩余油量为0
            }
  1. 更新当前累加剩余油量(curSum): curSum从上一个站点累加的剩余油量加上当前站点的剩余油量(gas[i] - cost[i])得到。

  2. 更新总累加剩余油量(totalSum): totalSum从上一个站点累加的剩余油量加上当前站点的剩余油量(gas[i] - cost[i])得到。

curSum的作用是判断从起始位置到达当前位置的路径是否可行。如果curSum小于0,说明从起始位置到达当前位置的路径不可行,因为从起始位置开始到当前位置油量一直不足,不可能顺利到达当前位置,更别说从当前位置继续走了。所以我们需要将起始位置更新为当前位置的下一个位置(i+1),并将curSum重置为0,相当于重新开始计算从新的起始位置到哪个位置的路径可行。

totalSum的作用是判断整个环路是否可行。如果totalSum小于0,说明所有站点的总剩余油量是负数,即无法完成一次环形行驶,返回-1即可。

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦 >人< 。

相关推荐
axxy20004 分钟前
leetcode之hot100---24两两交换链表中的节点(C++)
c++·leetcode·链表
chenziang111 分钟前
leetcode hot100 环形链表2
算法·leetcode·链表
若亦_Royi1 小时前
C++ 的大括号的用法合集
开发语言·c++
Captain823Jack2 小时前
nlp新词发现——浅析 TF·IDF
人工智能·python·深度学习·神经网络·算法·自然语言处理
Captain823Jack2 小时前
w04_nlp大模型训练·中文分词
人工智能·python·深度学习·神经网络·算法·自然语言处理·中文分词
Aileen_0v03 小时前
【AI驱动的数据结构:包装类的艺术与科学】
linux·数据结构·人工智能·笔记·网络协议·tcp/ip·whisper
是小胡嘛3 小时前
数据结构之旅:红黑树如何驱动 Set 和 Map
数据结构·算法
m0_748255023 小时前
前端常用算法集合
前端·算法
呆呆的猫3 小时前
【LeetCode】227、基本计算器 II
算法·leetcode·职场和发展
Tisfy3 小时前
LeetCode 1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解
算法·leetcode·优先队列·贪心·