134. 加油站

134. 加油站

✨核心逻辑

本题使用 贪心算法 的思想,只需要一次遍历就能找到唯一的出发点:

  1. 全局判断:如果所有加油站的总油量(totalGas)小于总耗油量(totalCost),即 totalGas < 0,说明无论从哪个站点出发都无法绕行一周,直接返回 -1
  2. 局部贪心:用一个变量 currentGas 记录从当前起点出发,到达当前站点时的油箱剩余油量。
  3. 重置起点:如果在行驶到站点 i 时,发现 currentGas < 0,说明从当前记录的起点到站点 i 这段区间内的任何一点出发,都无法跨越 i 这关。因此,直接抛弃这段区间,将下一个站点 i + 1 设为新的起点,并将 currentGas 重置为 0
  4. 最终答案:当遍历结束时,如果总油量是充足的,记录下的 start 索引就是唯一可行的出发点。

🔥代码实现(含详细变量注释)

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        // totalGas:记录所有加油站的油量总和减去所有路段的油耗总和
        // 如果最终 totalGas < 0,说明总油量不够,必然无法跑完一圈
        int totalGas = 0; 
        
        // currentGas:记录从当前起点 start 出发,目前油箱里剩下的油量
        int currentGas = 0; 
        
        // start:记录当前判断出的可行的起始加油站索引(初始默认为 0)
        int start = 0;  

        // i:遍历指针,依次走过每一个加油站
        for (int i = 0; i < cost.length; i++) {
            // diff:计算当前站点获得的油量 gas[i] 与前往下一站需要消耗的油量 cost[i] 的差值
            int diff = gas[i] - cost[i];
            
            // 累加差值到总油量和当前剩余油量中
            totalGas += diff;
            currentGas += diff;

            // 核心判断:如果到达当前站点 i 时,油箱里油量出现负数
            // 说明从当前的 start 到 i 之间的任意一点出发,都无法顺利通过 i 站
            // 因此将 i + 1 作为新的潜在出发点继续尝试
            if (currentGas < 0) {
                start = i + 1;
                currentGas = 0; // 重新从新起点出发,油箱清空,从 0 开始累加
            }
        }
        
        // 如果所有站点的净油量总和小于 0,则无解返回 -1;否则返回记录的有效起点 start
        return totalGas < 0 ? -1 : start;
    }
}
  • ⏱️复杂度分析
    • 时间复杂度:O(N),其中 N 是数组的长度。只需遍历数组一次,在循环内部进行常数次的加减和比较操作。

    • 空间复杂度:O(1),仅仅使用了 totalGas、currentGas、start、diff 和循环变量 i 等常数个整型变量,没有使用额外的数组空间。

🔍总结一下:

这道题采用贪心,看完答案还是有一个疑惑点: A-B 的路途中假设在B处油不够,为什么直接让起始start变成 B+1 而不是从之前A+1位置处重新走呢??

因为A能到B,说明中间的油一定有积累,从 A+1 开始少了A这部分余留的油一定到不了B!!

所以这道题就“贪”在这里