贪心算法
贪心算法的原理与步骤
你想了解的贪心算法,是编程和算法设计中一种核心的启发式策略,核心思路是“只顾眼前最优,不管全局后果”,但在特定问题上能高效找到全局最优解。下面我会用通俗易懂的方式讲解它的原理、步骤,并结合代码示例帮你理解。
一、贪心算法的核心原理
贪心算法的本质是:在每一步决策中,都选择当前状态下的“局部最优解”,并期望通过一系列局部最优的选择,最终得到整个问题的“全局最优解”。
可以用一个生活例子理解:你要从A地到B地,每次都选择当前看起来最近的路口走(局部最优),如果路线设计合理,最终能最快到达目的地(全局最优);但如果路线有“陷阱”(比如近路是死胡同),这种策略就会失败。
关键前提
贪心算法不是万能的,只有满足以下两个条件时,才能保证得到全局最优解:
- 贪心选择性质:局部最优选择能导出全局最优解(每一步的最优选择不依赖未来的决策)。
- 最优子结构:问题的全局最优解包含其子问题的最优解(可以把大问题拆成小问题,小问题的最优解能组合成大问题的最优解)。
二、贪心算法的通用步骤
贪心算法没有统一的代码模板,但解决问题的思路可以总结为4步,每一步都有明确的目标:
步骤1:明确问题的“最优解”定义
首先要清楚:你要优化的目标是什么?(比如“找最少的硬币凑出指定金额”“求最大的活动安排数量”)。
例:硬币找零问题的最优解定义是“使用最少数量的硬币凑出目标金额”。
步骤2:确定“局部最优”的选择策略
这是贪心算法的核心——设计一个规则,让每一步都能选出当前最优的选项。
例:
- 硬币找零(硬币面额为[1,5,10,25]):每次选面额最大的硬币(局部最优)。
- 活动安排问题:每次选结束时间最早的活动(局部最优)。
步骤3:验证策略的有效性(关键)
必须确认你设计的“局部最优”策略能推导出“全局最优”,否则贪心算法不适用。
⚠️ 反例:如果硬币面额是[1,3,4],目标金额是6,按“选最大面额”的策略会选4+1+1(共3枚),但最优解是3+3(仅2枚)——此时贪心策略失效,需用动态规划。
步骤4:实现算法(迭代/递归)
根据确定的策略,逐步执行选择,直到满足问题的终止条件(比如凑出目标金额、选完所有可行活动)。
三、经典示例:活动安排问题(贪心算法的典型应用)
问题描述
有n个活动,每个活动有开始时间s[i]和结束时间f[i],同一时间只能参加一个活动,求能参加的最大活动数量。
贪心策略
每次选择结束时间最早的活动(局部最优),这样能留出更多时间给后续活动,最终得到全局最优。
完整代码实现(Python)
def greedy_activity_selector(s, f):
"""
贪心算法解决活动安排问题
:param s: 活动开始时间列表
:param f: 活动结束时间列表(需提前按结束时间排序)
:return: 选中的活动索引列表
"""
n = len(s)
if n == 0:
return []
# 步骤1:初始化,先选第一个活动(结束时间最早)
selected = [0]
last_finish = f[0] # 记录上一个选中活动的结束时间
# 步骤2:遍历剩余活动,选择局部最优
for i in range(1, n):
# 局部最优规则:当前活动开始时间 >= 上一个活动结束时间(不冲突)
if s[i] >= last_finish:
selected.append(i)
last_finish = f[i] # 更新最后结束时间
return selected
# 测试用例
if __name__ == "__main__":
# 活动结束时间已排序(关键前提)
s = [1, 3, 0, 5, 8, 5] # 开始时间
f = [2, 4, 6, 7, 9, 9] # 结束时间(已排序)
result = greedy_activity_selector(s, f)
print("选中的活动索引:", result) # 输出:[0,1,3,4]
print("选中的活动时间:")
for i in result:
print(f"活动{i}:开始{s[i]},结束{f[i]}")
代码解释
- 前提处理:活动列表必须按结束时间排序(这是贪心策略生效的基础);
- 初始选择:先选结束时间最早的活动(索引0),作为第一个局部最优解;
- 迭代选择:遍历后续活动,只要当前活动的开始时间不早于上一个活动的结束时间(不冲突),就选中它(继续局部最优);
- 结果输出:最终选中的活动列表就是能参加的最大数量(全局最优)。
输入输出说明
- 输入:开始时间
[1,3,0,5,8,5],结束时间[2,4,6,7,9,9]; - 输出:选中活动索引
[0,1,3,4],对应活动时间为(1,2)、(3,4)、(5,7)、(8,9),共4个活动(全局最优)。
四、贪心算法的适用场景
贪心算法适合解决“组合优化类问题”,常见应用:
- 硬币找零(面额为标准进制,如1/5/10/25);
- 活动安排/任务调度;
- 哈夫曼编码(数据压缩);
- 最小生成树(Prim算法、Kruskal算法);
- 最短路径(Dijkstra算法)。
总结
- 核心逻辑:每一步选“局部最优”,通过验证后可推导出“全局最优”,核心是贪心选择策略的设计;
- 关键前提:问题必须满足“贪心选择性质”和“最优子结构”,否则贪心算法会失效;
- 实现步骤:定义最优解→设计局部策略→验证有效性→迭代执行。
贪心算法的优势是时间复杂度低(通常为O(n)或O(n log n)),但缺点是对问题的适配性强——只有选对了“局部最优”的规则,才能得到正确结果。

浙公网安备 33010602011771号