贪心算法核心定理与应用------以 Gas Station 问题为例
一、定理简述
定理:
如果从站点 A 出发由于油箱空了无法走到站点 B,那么从 A 和 B 之间的任何站点 C 出发,也绝不可能到达 B。
二、数值例子与反证
假设站点有 0, 1, 2, 3,从站点 0 开始,如果油量不足导致走不到站点 3:
站点: 0 1 2 3
↓ ↓ ↓ ↓
油差: -2 +1 -3
从0出发累积:
0→1: tank = -2
1→2: tank = -2+1 = -1
2→3: tank = -1-3 = -4 < 0 ← 失败!
反证法:假设从1能到3
1→2: +1
1→3: +1-3 = -2 < 0 ← 也失败!
原因其实很明确:
从1到3的累积 = 从0到3的累积 - 从0到1的累积 = -4 - (-2) = -2 < 0
**结论:**从 1 出发也到不了 3
三、数学证明(简洁版)
-
定义
sum(A,B)表示从 A 到 B 的总油量 -
已知
sum(A,B) < 0(A 走不到 B) -
求证
对于任意 C(A < C < B),
sum(C,B) < 0 -
证明
sum(A,B) = sum(A,C) + sum(C,B) 即 sum(C,B) = sum(A,B) - sum(A,C) 由于从 A 到 C 能走到,所以 sum(A,C) >= 0 所以 sum(C,B) < sum(A,B) - 0 < 0结论成立 ------ 从 C 也到不了 B
四、图解与类比
以爬山为例:
- A站在山脚,B在山顶,C在半山腰
- 如果从 A 带着体力都爬不到 B
- 那么从 C 体力为0更无法爬到 B!
五、定理在算法代码中的应用
c
if (current_tank < 0) {
start = i + 1;
current_tank = 0;
}
含义:
一旦发现从 start 走不到 i,直接将新起点跳到 i+1,start 到 i 之间的所有点都无需再试!
六、完整例子讲解
如:
gas = [1,2,3,4,5], cost = [3,4,5,1,2]
- 从 0 出发失败,跳到 1
- 从 1 失败,跳到 2
- 从 2 失败,跳到 3
- 从 3 成功一圈,返回 3
其中跳过的起点都无需单独模拟,直接跳过,方式高效。
七、结论总结
定理:
如果从A走不到B,A和B之间的任一点也走不到B
应用精髓:
- 一旦出现当前累积油量 < 0,直接贪心跳到下一个起点
- 不回溯,不暴力逐个尝试
一句话总结:
如果带着非负的累积都到不了终点,那么从中间零累积出发更到不了终点!
八、为什么这是贪心算法?
贪心算法特征
- 每步选择局部最优解
- 不回溯
- 希望局部最优导致全局最优
Gas Station 问题的贪心策略:
c
if (current_tank < 0) {
start = i + 1; // 贪心跳到下一个
current_tank = 0;
}
一旦发现当前起点失败,立即把可能的起点一锅端,"贪"地跳过这些无效区间。
对比:贪心 vs 暴力
| 方法 | 过程 | 时间复杂度 | 说明 |
|---|---|---|---|
| 暴力法 | 每个起点都尝试一圈 | O(n²) | 保守、低效 |
| 贪心法 | 一次遍历跳过不可能区间 | O(n) | 高效、智能跳过 |
九、贪心算法的正确性与共性
满足:
- 最优子结构
- 贪心选择性质
- 无后效性
与最小硬币找零、Jump Game、活动选择、霍夫曼编码等贪心题型核心思想一致
十、最终总结
Gas Station 是贪心算法,因为它贪婪地跳过不可能的起点,而不是保守逐个尝试。基于数学定理保证了跳过的安全性,时间复杂度大幅降低为 O(n)。这种"大胆跳过一段"的策略就是贪心算法的精髓!
如果你觉得有启发,欢迎点赞/收藏/留言!更多贪心算法实战和原理解读,尽在我的CSDN专栏!