🪙

贪心算法

每次只选"眼前最大"的那一步——快,但不一定最优

💡 打个比方

商店找你 6 元钱,你手里有 1 元、3 元、4 元三种硬币。贪心的想法很简单:每次都拿手里最大的。

按贪心来:先拿 4 元 → 还差 2 元,只能拿 1 元 → 还差 1 元,再拿 1 元。一共 3 枚(4+1+1)。

可是等一下——如果先拿 3 元,还差 3 元,再拿一枚 3 元,2 枚就找完了(3+3)!"先拿最大的"这次反而吃亏了。

贪心就是每一步都选当前看起来最好的选择,不往前看全局。它简单、飞快,但不一定是最优解。什么时候能用贪心?看题目有没有最优子结构:大问题拆成小问题后,每个小问题各自做到最优,拼起来恰好就是整体最优——这时候贪心才敢用。

贪心两问:① 这一步选"当前最大/最近/最便宜",后面会不会后悔?② 小问题各自最优,拼起来是不是整体最优?两问都有把握,贪心才用;否则要老老实实枚举或动态规划。

🖼️ 大图看明白

① 贪心找零一步步走(硬币:50 25 10 5 1,找 68 元) 50 25 10 5 1 贪心步骤 贪心结果 最优 找 68 元 拿 50 → 剩 18 拿 10 → 剩 8 拿 5 → 剩 3 拿 1 三次 → 剩 0 共 6 枚 面额"老实"(像真实货币)时,贪心每次都能给出最少枚数。 ② 反例:硬币 {1, 3, 4},找 6 元——贪心不一定最优 贪心:每次拿最大 4 1 1 3 枚 4 + 1 + 1 VS 最优:3 + 3 3 3 2 枚 3 + 3 贪心"先拿 4"后剩下 2,只能拆成 1+1;先拿 3+3 两枚就够了。 所以:用贪心之前,先用小例子验证它真的最优。

📏 怎么用贪心:只要 3 步

第 1 步:找出每一步的"局部最优"规则——拿最大的、选最近的、挑最便宜的。规则要一句话能说清楚,比如"每次拿不超过剩余金额的最大硬币"。

第 2 步:拿小例子验证!把规则手算一遍,再专门找反例(换个数字、换个面额再试)。像 4+1+1 vs 3+3 这样的反例一出现,贪心就不一定最优,得换方法。

第 3 步:写一个循环:每轮挑当前局部最优 → 更新剩下的问题 → 重复,直到问题清零。贪心不回头、不比较,所以特别快(找零只要 O(硬币种类×枚数) 次比较)。

提醒:贪心快,但"快"不等于"对"。能证明"局部最优拼起来就是全局最优"(最优子结构),才放心用;证明不了,就老老实实枚举。

💻 C++ 怎么写

// 贪心找零:每次拿不超过剩余金额的最大硬币
int coins[] = {50, 25, 10, 5, 1};  // 面额,从大到小
int money = 68, total = 0;         // 要找的钱、已用枚数
while (money > 0) {
    int pick = 1;                  // 兜底:1 元一定能拿
    for (int i = 0; i < 5; i++) {
        if (coins[i] <= money) {   // 找到最大的可用硬币
            pick = coins[i];
            break;                 // 面额从大到小,第一个就是最大
        }
    }
    money -= pick;                 // 更新剩余金额
    total++;                       // 枚数加 1
}
cout << total << endl;             // 输出 6(50+10+5+1+1+1)
考点:贪心不一定最优。同样的代码换成面额 {4, 3, 1}、money = 6,会输出 3(4+1+1),但最优是 3+3 只要 2 枚。真实货币面额设计得"老实",贪心才对;题目给的硬币不老实,先找反例。

✋ 你来试试

题 1:把找零代码的面额换成 {4, 3, 1},找 10 元,代码输出几枚?这是最优吗?
代码会输出 4 枚:4(剩 6)→ 4(剩 2)→ 1(剩 1)→ 1(剩 0)。但最优是 3 枚:4 + 3 + 3 = 10。贪心每次都拿"最大的 4",两次 4 之后剩下 2 只能拆 1+1,反而不如"留一个 3"划算——这就是没有最优子结构时贪心翻车的典型样子。
题 2:贪心为什么比"把所有组合都试一遍"快得多?它什么时候会错?
因为贪心每步只选一次、不回头:试所有组合要把每种拆法都数一遍(指数级),贪心每枚硬币只比较一遍面额(线性级别),所以飞快。它会错的时候只有一种:局部最优拼不出全局最优——即不存在最优子结构,比如 {1,3,4} 找 6 元时"先拿 4"堵死了 3+3 的路。所以考试里见到贪心题,先问"有没有反例"。
🎯 一句话记住:贪心 = 每步拿局部最优 + 小例子找反例验证;快但不一定最优;有最优子结构才敢放心用。