Leetcode 加油站

当然,以下是这个 Java 代码的算法思想的中文解释:

算法思路

这道题目要求我们找到一个出发的加油站,使得汽车能环绕一圈回到该站。如果没有这样的加油站,则返回 -1。算法的核心思想是贪心算法(Greedy Algorithm),利用总油量和当前油量的平衡来确定可能的起点。

代码解析

  1. 定义变量

    • totalGas:表示整个环形路程中,提供的油量和消耗的油量的总差。如果 totalGas 最终是负数,说明总油量不足以支持环绕一圈,因此直接返回 -1
    • currentGas:表示从当前起点出发,到当前加油站的油量盈余。如果 currentGas 变为负数,说明从当前起点出发无法到达下一个加油站,此时我们需要更换起点。
    • startStation:记录当前的起点加油站索引。
  2. 循环遍历所有加油站

    • totalGas += gas[i] - cost[i];:累计总油量盈余。
    • currentGas += gas[i] - cost[i];:累计当前起点到当前加油站的油量盈余。
    • 如果 currentGas 变为负数,说明从当前起点 startStation 出发无法到达当前加油站 i 的下一个加油站,因此将 startStation 更新为 i + 1,并将 currentGas 重置为 0,表示重新从下一个加油站开始尝试。
  3. 判断结果

    • 如果 totalGas 是非负数,说明油量总和足够支持环绕一圈,此时返回 startStation 作为起点。
    • 如果 totalGas 是负数,说明无论从哪个加油站出发,总油量都不足以环绕一圈,因此返回 -1

算法复杂度

这个算法只需遍历数组一次,因此时间复杂度为 (O(n)),其中 (n) 是加油站的数量,效率很高。

总结

该算法通过两次油量平衡检查(一次全局平衡,一次局部平衡),利用贪心策略有效地判断并找到唯一的可能起点。

java solution

java 复制代码
class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int totalGas = 0;
        int currentGas = 0;
        int startStation = 0;
        for(int i = 0; i < gas.length; i++) {
            totalGas += gas[i] - cost[i];
            currentGas += gas[i] - cost[i];
            if(currentGas < 0) {
                startStation = i + 1;
                currentGas = 0;
            }
        }
        return totalGas >= 0 ? startStation : -1;
    }
}

既然是环路,为什么只需要一个for循环就可以保证得到最终结果?

这是一个很好的问题!确实,在处理环路问题时,我们通常会考虑两次遍历甚至更多遍历,但在这道题中,只需一次遍历就能解决问题,这是因为算法的设计巧妙利用了贪心思想。让我来详细解释为什么一个 for 循环就可以保证得到最终结果。

为什么只需要一次遍历?

核心原因在于总油量和局部油量的平衡。下面我们逐步拆解这个逻辑:

  1. 全局油量平衡totalGas):

    • 如果总油量大于或等于总消耗量(即 totalGas >= 0),那么理论上一定存在一个起点可以使汽车顺利环绕一圈。这是因为,只要总油量足够,那么只要找到合适的起点,汽车就可以顺利行驶。
    • 如果总油量小于总消耗量(即 totalGas < 0),那么无论从哪个加油站出发,汽车都无法环绕一圈。因此,totalGas 是用来判断是否存在解的关键。
  2. 局部油量平衡currentGas):

    • currentGas 用来记录从当前起点 startStation 出发,到当前加油站位置 i 的油量盈余。
    • currentGas 在某个加油站位置变为负数时,意味着从当前 startStation 出发无法继续到下一个加油站。因此,这时候就需要重新选择新的起点,即将 startStation 更新为 i + 1,并将 currentGas 重置为 0
    • 换句话说,当我们发现从某个起点无法到达下一个加油站时,说明这个起点以及它之前的任何加油站都不可能作为有效的起点,因为如果它们可以,currentGas 就不会为负数。因此,我们可以直接跳到下一个加油站作为新的起点,而不需要重新遍历之前的加油站。
  3. 贪心策略的关键

    • 当我们选择一个新的 startStation 时,之前所有的加油站都被"放弃"了,因为我们已经知道从这些站点出发无法完成环绕一圈。
    • 最终,如果整个数组遍历完毕且 totalGas >= 0,那么最后确定的 startStation 就是唯一可能的起点。

例子分析

以题目中的例子为例:

  • gas = [1, 2, 3, 4, 5]
  • cost = [3, 4, 5, 1, 2]
  1. 我们初始化 startStation = 0totalGas = 0currentGas = 0
  2. 依次遍历加油站:
    • 当遍历到第 2 号加油站时(i = 2),currentGas 变为负数,这表明从 startStation = 0 出发无法到达下一个站。因此,我们将 startStation 更新为 i + 1 = 3
    • 从第 3 号加油站重新出发,直到遍历结束,currentGas 不再为负数。
  3. 最后检查 totalGas >= 0,确定可以环绕一圈,因此返回 startStation = 3

总结

这个算法的关键在于每当 currentGas 变为负数时,说明从当前起点以及之前的所有加油站出发都无法成功。通过将起点移动到下一个加油站,我们避免了重复计算,因此只需要一次遍历就能确定唯一的可能起点。

相关推荐
吾店云建站10 分钟前
使用ACF插件向WooCommerce商城产品添加自定义字段
程序人生·职场和发展·创业创新·流量运营·程序员创富
jianbaigreat1 小时前
代码随想录打卡Day22、23、24、25
数据结构·算法
Ddddddd_1581 小时前
C++ | Leetcode C++题解之第560题和为K的子数组
c++·leetcode·题解
_OLi_1 小时前
力扣 LeetCode 206. 反转链表(Day2:链表)
算法·leetcode·链表
运维&陈同学1 小时前
【HAProxy05】企业级反向代理HAProxy调度算法之静态算法与动态算法
linux·运维·算法·nginx·云原生·负载均衡·lvs·haproxy
weixin_478689761 小时前
【贪心算法】——力扣763. 划分字母区间
算法·leetcode·贪心算法
sp_fyf_20241 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-03
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
友大冰2 小时前
前端开发中的CSS框架:昔日辉煌与新兴潮流
前端·css·算法·开源·tensorflow
nuyoah♂2 小时前
DAY27|贪心算法Part01|LeetCode:455.分发饼干、376. 摆动序列、53. 最大子序和
算法·leetcode·贪心算法
十七算法实验室2 小时前
Matlab实现鼠群优化算法(ROS)求解路径规划问题
开发语言·算法·决策树·支持向量机·matlab·动态规划·启发式算法