贪心算法故事:拖延症小明的作业危机

贪心算法就像一位"永远只选眼前最优解"的冒险家,每次决策都选择当下最有利的选项,逐步逼近全局最优解。下面我用一个​​拖延症学生赶作业​​的故事,带你彻底理解其精髓!


📖 ​​故事:拖延症小明的作业危机​​

小明周日晚上才发现有5项作业没做,每项耗时不同:
数学(60分钟), 语文(30分钟), 英语(15分钟), 物理(45分钟), 化学(20分钟)

他要在2小时内(120分钟)完成尽可能多的作业。

⚡ ​​贪心策略​​:

​​每次都选当前耗时最短的作业​​(快速清掉小任务,腾出更多时间)

  1. 选最短:​英语(15min)​ → 剩余时间105min
  2. 选次短:​化学(20min)​ → 剩余85min
  3. 选第三短:​语文(30min)​ → 剩余55min
  4. 选第四短:​物理(45min)​ → 剩余10min
  5. 数学需60min(但剩余时间不足)→ 放弃

​​结果​​:完成4项作业(总耗时110min),比按顺序做(只能做3项)更优!


⚙️ ​​贪心算法核心原理​​

​​1. 两大黄金定律​​

​​特性​​ ​​含义​​ ​​小明例子​​
​​贪心选择性质​​ 局部最优选择能导向全局最优解 每次选最短作业 → 完成总数最多
​​最优子结构​​ 大问题的最优解由子问题最优解组成 完成4项 = 前4项最优解的组合

​​2. 与动态规划的区别​​

💡 贪心永不回溯(高效但可能非全局最优),动态规划会回看历史(准确但更慢)


💻 ​​Java代码实战:作业调度贪心算法​​

typescript 复制代码
java
Copy
import java.util.*;  

public class GreedyHomework {  
    public static void main(String[] args) {  
        // 作业列表:<科目, 耗时>  
        Map<String, Integer> homework = new HashMap<>();  
        homework.put("数学", 60);  
        homework.put("语文", 30);  
        homework.put("英语", 15);  
        homework.put("物理", 45);  
        homework.put("化学", 20);  

        // 贪心核心:按耗时升序排序  
        List<Map.Entry<String, Integer>> sortedList = new ArrayList<>(homework.entrySet());  
        sortedList.sort(Map.Entry.comparingByValue()); // 按耗时排序[11](@ref)  

        // 执行作业  
        int totalTime = 120;  
        List<String> completed = new ArrayList<>();  
        for (Map.Entry<String, Integer> task : sortedList) {  
            if (totalTime >= task.getValue()) {  
                completed.add(task.getKey());  
                totalTime -= task.getValue();  
            } else {  
                break; // 时间不足时停止  
            }  
        }  

        System.out.println("完成作业:" + completed);  
        System.out.println("剩余时间:" + totalTime + "分钟");  
    }  
}  

​​运行结果​​:

css 复制代码
Copy
完成作业:[英语, 化学, 语文, 物理]  
剩余时间:10分钟  

⚠️ ​​贪心算法的陷阱:何时会失效?​​

​​1. 非标准货币找零问题​​

若硬币面额为:[1, 5, 11],要凑出​​15元​​:

  • 贪心:11+1+1+1+1 → ​​5枚硬币​​

  • 实际最优:5+5+5 → ​​3枚硬币​​(贪心失效!)

​​2. 适用条件总结​​

​​场景​​ ​​是否适用贪心​​ ​​原因​​
标准找零(1/5/10) ✅ 是 大面额总能组成最优解
非标准找零 ❌ 否 局部最优≠全局最优
活动安排问题 ✅ 是 早结束的活动优先保证更多安排8
背包问题(物品可分割) ✅ 是 优先选价值密度最高的物品

🚨 ​​黄金法则​ ​:使用前必须证明问题满足​​贪心选择性质​​!


🌐 ​​经典应用场景与Java实现​​

​​1. 活动安排问题(最多不相交区间)​​

ini 复制代码
java
Copy
// 按结束时间排序 → 每次选最早结束的活动[8,10](@ref)  
Arrays.sort(activities, (a, b) -> a.end - b.end);  
int count = 1, lastEnd = activities[0].end;  
for (int i = 1; i < activities.length; i++) {  
    if (activities[i].start >= lastEnd) {  
        count++;  
        lastEnd = activities[i].end;  
    }  
}  

​​2. 股票买卖(多次交易)​​

ini 复制代码
java
Copy
// 只要今天比昨天涨就卖出[5](@ref)  
int profit = 0;  
for (int i = 1; i < prices.length; i++) {  
    if (prices[i] > prices[i - 1]) {  
        profit += prices[i] - prices[i - 1];  
    }  
}  

​​3. 霍夫曼编码(数据压缩)​​

优先合并频率最小的字符 → 构建最优前缀树


💎 ​​总结:一图掌握贪心算法​​

​​面试口诀​​:

眼前利益最大化,全局最优需验证。

活动排序找零钱,子结构是通行证!

试着运行文中的作业调度代码,调整时间限制和作业时长,观察贪心策略的变化。记住:​​贪心算法是面试高频考点,重点在于识别问题是否具备贪心选择性质!​

相关推荐
大圣编蚕5 小时前
初探 NDK 的世界:从零开始理解 Android 原生开发
android
云贝贝贝5 小时前
MySQL 慢查询定位与索引优化实战
android
骑着蜗牛撵大象3276 小时前
服务下线不再炸:分层关闭、TCP 存活探测与负载均衡排水的落地套路
android·tcp/ip·负载均衡·tcp·高可用·健康检查·优雅关闭
三少爷的鞋8 小时前
别再这么写协程了!Marcin Moskała 剖析的 几个常见协程误区与重构
android
mmsx9 小时前
Android 防二次打包第一道锁:签名校验与完整性校验
android·kotlin
mmsx9 小时前
Android 混淆不等于安全:二次打包链路完整走一遍
android·kotlin
小宋102111 小时前
Agent轨迹级评测实战:工具选择、预算超限与回归门禁
android·网络·人工智能·回归
墨天梦13 小时前
D05_ViewModel与单向数据流
android·kotlin
蒸鱼Yuzheng14 小时前
Android 构建可复现性:APK 指纹、文件级差异与供应链审计
android·apk·devops·软件供应链·可复现构建
墨天梦16 小时前
D03_Compose列表与稳定身份
android·gitee·kotlin