LeetCode 134. 加油站(贪心算法详解 + C语言实现)

一、题目描述

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

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

你从某一个加油站出发,初始油箱为空。

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

题目保证如果存在解,则 解是唯一的


二、思路分析(贪心算法)

首先考虑一个关键问题:

如果 所有加油站的总油量 < 总消耗油量,那么无论从哪里出发都不可能绕一圈。

因此:

复制代码
sum(gas) >= sum(cost) 才可能有解

接下来思考如何找到起点。

我们定义:

复制代码
diff[i] = gas[i] - cost[i]

表示在第 i 个加油站加油后前往下一个站的 净油量变化

然后遍历数组,并维护两个变量:

  • total:整个环路的油量盈余

  • tank:当前起点到当前位置的剩余油量

遍历过程:

  1. 累加 diff

  2. 如果 tank < 0,说明:

    • 当前起点无法到达 i+1

    • 当前起点到 i 之间的任何站都不可能成为起点

因此可以直接把起点更新为:

复制代码
start = i + 1

并把当前油量清零重新计算。


三、贪心策略为什么正确?

假设从 start 出发,到 i 时油量变为负数:

复制代码
tank < 0

说明:

复制代码
gas[start] + gas[start+1] + ... + gas[i]
<
cost[start] + cost[start+1] + ... + cost[i]

那么如果从 start+1start+2 ... i 作为起点,情况只会更糟。

因此:

这些位置都不可能成为合法起点,可以直接跳过。

所以我们直接从 i+1 重新开始尝试。


四、算法步骤

  1. 遍历所有加油站

  2. 计算 diff = gas[i] - cost[i]

  3. 更新 totaltank

  4. 如果 tank < 0

    • 起点更新为 i+1

    • tank = 0

  5. 遍历结束后

    • 如果 total >= 0 返回 start

    • 否则返回 -1


五、C语言代码实现

复制代码
int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize) {
    int total = 0;   // 总油量差
    int tank = 0;    // 当前油量
    int start = 0;   // 起点

    for (int i = 0; i < gasSize; i++) {
        int diff = gas[i] - cost[i];
        total += diff;
        tank += diff;

        // 当前起点无法继续前进
        if (tank < 0) {
            start = i + 1;
            tank = 0;
        }
    }

    if (total >= 0)
        return start;
    else
        return -1;
}

六、复杂度分析

时间复杂度

复制代码
O(n)

只遍历一次数组。

空间复杂度

复制代码
O(1)

只使用常数级变量。


七、总结

本题核心有两个关键点:

1️⃣ 总油量必须 ≥ 总消耗油量

否则一定无解。

2️⃣ 贪心选择起点

一旦当前起点无法到达某个位置,则:

复制代码
start ~ i 之间的所有点都不可能成为起点

因此直接从 i+1 重新开始。

该方法只需一次遍历即可解决问题,是本题的 最优解法


相关推荐
汀、人工智能1 小时前
[特殊字符] 第21课:最长有效括号
数据结构·算法·数据库架构·图论·bfs·最长有效括号
Boop_wu1 小时前
[Java 算法] 字符串
linux·运维·服务器·数据结构·算法·leetcode
故事和你912 小时前
洛谷-算法1-2-排序2
开发语言·数据结构·c++·算法·动态规划·图论
Fcy6482 小时前
算法基础详解(三)前缀和与差分算法
算法·前缀和·差分
kvo7f2JTy2 小时前
基于机器学习算法的web入侵检测系统设计与实现
前端·算法·机器学习
List<String> error_P3 小时前
蓝桥杯最后几天冲刺:暴力大法(一)
算法·职场和发展·蓝桥杯
Hou'3 小时前
从0到1的C语言传奇之路
c语言·开发语言
迈巴赫车主4 小时前
蓝桥杯3500阶乘求和java
java·开发语言·数据结构·职场和发展·蓝桥杯
流云鹤4 小时前
Codeforces Round 1090 (Div. 4)
c++·算法
wljy14 小时前
第十三届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(个人见解,已完结)
c语言·c++·算法·蓝桥杯·stl