贪心法
贪心法(Greedy)每一步都做当前看起来最优的选择,并期望由此得到全局最优(或足够好的近似解)。
本文解决什么问题
- 贪心在什么条件下可能正确
- 如何用反例判断「不能贪」
- 本教程后续哪些算法属于贪心族
适用直觉
能贪心的问题往往(需要证明)具有:
- 贪心选择性质:局部最优选择可以成为某全局最优解的一部分
- 最优子结构:最优解包含子问题的最优解
这两点不是口号——不是所有问题都能贪心。拿不准时:
- 先尝试构造反例
- 反例存在 → 换 DP 或其他方法
- 反例找不到 → 再查证明或权威结论
例子:找零(经典币值可用贪心)
币值为 时,每次选不超过余额的最大面额:
int coin_change_greedy(int amount) {
const int coins[] = {25, 10, 5, 1};
int count = 0;
for (int i = 0; i < 4; i++) {
count += amount / coins[i];
amount %= coins[i];
}
return count;
}
对「美元常见面额」这类集合,贪心是正确的。但若币值改成例如 ,要凑 :
- 贪心: → 3 枚
- 最优: → 2 枚
贪心失败。任意币值的最少枚数通常用 动态规划。