🎭 故事名:《现实主义者小贪的财富冒险》
🧭 背景设定:
在遥远的计算国中,有一位名叫 小贪 的商人。他不是那种喜欢深思熟虑的人,也不爱做复杂的计划。他有一个信条:
“我只选眼前看起来最划算的那一笔买卖。”
于是他背上行囊,踏上旅程,去寻找“最快发财”的方法。
🧠 这正是 贪心算法的核心思想:
-
每一步都选择当前最优解
-
不回头考虑之前的决策
-
期望通过一系列局部最优解达到全局最优
🛒 第一幕:初入市场,快速交易
小贪来到第一个村庄,看到市场上有三种商品可以买卖:
商品 | 成本价 | 卖出价 | 利润 |
---|---|---|---|
苹果 | ¥2 | ¥5 | +¥3 |
香蕉 | ¥3 | ¥6 | +¥3 |
橘子 | ¥4 | ¥7 | +¥3 |
他没有犹豫:“哪个利润高就买哪个!”但三个都一样……
🧠 对应代码逻辑:
选择最大利润的商品 = max(苹果, 香蕉, 橘子)
虽然没赚最多,但他节省了时间!
🕰️ 第二幕:时间有限,效率第一
小贪继续前行,来到了一个限时集市。这里每种商品都有交易时间限制,他只能选几样。
他看了看,发现:
商品 | 时间 | 收益 |
---|---|---|
A | 1h | ¥100 |
B | 2h | ¥180 |
C | 3h | ¥240 |
他想:“我要尽可能在最短时间内赚最多的钱。”于是选择了 A → B → C。
🧠 对应贪心策略:
-
按照单位时间收益排序(A:100/h,B:90/h,C:80/h)
-
优先选择单位收益高的商品
这就是经典的 活动选择问题 / 区间调度问题。
💰 第三幕:金币兑换,贪心失效
来到王城,小贪遇到了一个新的挑战:用最少的硬币支付某个金额。
当前货币系统是:
[1, 5, 10, 25]
(美分制)
他要支付 30 分钱,怎么选?
他立刻选了:1个 25 分 + 1个 5 分 → 只需两枚硬币 ✅ 这正是贪心策略成功的例子。
🧠 但在某些货币体系下会失败,比如:
-
硬币面额为
[1, 3, 4]
-
目标金额为
6
贪心法:4 + 1 + 1 → 3 枚 最优解:3 + 3 → 2 枚 ❌
🧠 所以说:贪心不一定总是正确的
📈 第四幕:股票交易,贪心显神威
小贪听说股市能赚钱,便决定研究一下。
他看到价格走势如下:
[7, 1, 5, 3, 6, 4]
他决定:“只要今天比昨天便宜,我就买;只要明天涨了,我就卖。” 于是他在第2天买入(1元),第3天卖出(5元),第4天再买入(3元),第5天卖出(6元)。总共赚了:4 + 3 = 7元!
🧠 对应 LeetCode 股票 II 题目:
for (int i = 1; i < prices.size(); ++i) {
if (prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1];
}
}
✨ 第五幕:最终总结
小贪回顾自己的旅程,得出结论:
-
在很多情况下,贪心策略确实能让他快速做出决策;
-
有时候还能得到最优解;
-
但也有不少时候,它并不准确;
-
但它最大的优点是:快!省时间!
🧠 所以贪心适用于:
-
活动选择问题(如会议安排)
-
区间调度问题(如任务分配)
-
哈夫曼编码(压缩算法)
-
背包问题的近似解
-
股票交易最大化收益(无限次交易)
🧠 总结:现实主义者视角 vs 程序员视角
商人视角 | 程序员视角 |
---|---|
选择眼前最划算的买卖 | 每一步取当前最优解 |
不回头思考以前的选择 | 不进行回溯或记忆化 |
有时赚得多,有时亏点 | 局部最优不一定等于全局最优 |
快速做决策 | 时间复杂度低,常为 O(n log n) 或 O(n) |
✅ 示例代码(LeetCode 122. 买卖股票的最佳时机 II):
#include <iostream>
#include <vector>
using namespace std;
int maxProfit(vector<int>& prices) {
int profit = 0;
for (int i = 1; i < prices.size(); ++i) {
if (prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1];
}
}
return profit;
}
int main() {
vector<int> prices = {7, 1, 5, 3, 6, 4};
cout << "最大收益:" << maxProfit(prices) << endl;
return 0;
}