Python学习算法系列(7):动态规划与贪心算法

Python学习算法系列(7):动态规划与贪心算法

1. 引言

动态规划(Dynamic Programming,DP)贪心算法(Greedy Algorithm) 是两种常见的算法设计思想。它们在许多优化问题中有广泛的应用,能够帮助我们高效地求解最优解。

本篇博客将介绍:

  • 动态规划的基本思想
  • 贪心算法的基本思想
  • 动态规划与贪心算法的应用场景

2. 动态规划(Dynamic Programming)

2.1 动态规划的基本思想

动态规划是通过将一个复杂问题分解为子问题,并将每个子问题的解存储下来,避免重复计算,从而提高效率。动态规划主要适用于最优化问题,例如求最短路径、最大子数组和等。

动态规划的核心
  • 最优子结构:问题的最优解可以通过子问题的最优解来构建。
  • 子问题重叠:子问题的解可以多次复用。

2.2 动态规划实现示例:斐波那契数列

斐波那契数列的递归实现效率较低,而使用动态规划能够显著提高效率。

def fibonacci(n):
    # 创建一个存储计算结果的数组
    dp = [0] * (n + 1)
    
    # 基础情况
    dp[0], dp[1] = 0, 1
    
    # 迭代计算斐波那契数
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    
    return dp[n]

# 测试动态规划版的斐波那契数列
n = 10
print(f"Fibonacci({n}) = {fibonacci(n)}")  # 输出 Fibonacci(10) = 55
解释
  • 我们用一个数组 dp 来存储每个子问题的解。通过从 dp[2] 开始迭代,直到计算出 dp[n],从而求出斐波那契数列的第 n 项。
  • 时间复杂度:O(n),空间复杂度:O(n)。

2.3 动态规划的典型问题

  • 背包问题:给定一组物品,每个物品有重量和价值,如何选择物品使得总重量不超过背包容量,且总价值最大。
  • 最长公共子序列:给定两个字符串,求它们的最长公共子序列(LCS)。
  • 最短路径问题:如Dijkstra算法

3. 贪心算法(Greedy Algorithm)

3.1 贪心算法的基本思想

贪心算法的核心思想是每次选择当前最优解,从而期望通过局部最优的选择得到全局最优解。贪心算法适用于满足贪心选择性质的问题,即每次选择都是最优的,且选择的局部最优解能导致全局最优解。

贪心算法的核心
  • 贪心选择性质:每一步的局部选择都是最优的。
  • 最优子结构:问题的最优解由子问题的最优解构成。

3.2 贪心算法实现示例:活动选择问题

活动选择问题是经典的贪心算法问题:给定一组活动,每个活动有开始和结束时间,选择最大数量的互不冲突的活动。

def activity_selection(start, finish):
    n = len(start)
    activities = list(range(n))
    
    # 根据结束时间排序
    activities.sort(key=lambda i: finish[i])
    
    # 选择活动
    selected_activities = []
    last_end_time = -1
    for i in activities:
        if start[i] >= last_end_time:
            selected_activities.append(i)
            last_end_time = finish[i]
    
    return selected_activities

# 测试活动选择问题
start = [1, 3, 0, 5, 8, 5]
finish = [2, 4, 6, 7, 9, 9]
selected = activity_selection(start, finish)
print(f"选择的活动编号:{selected}")  # 输出 [0, 1, 3, 4]
解释
  • 活动按结束时间排序,每次选择第一个不与前一个活动冲突的活动。
  • 时间复杂度:O(n log n)(排序)。

3.3 贪心算法的典型问题

  • 活动选择问题
  • 霍夫曼编码
  • 贪心背包问题

4. 动态规划与贪心算法的区别

特点动态规划贪心算法
适用问题最优化问题,子问题重叠最优化问题,满足贪心选择性质
方法通过子问题的解构建整体解每一步做出最优选择,不回溯
时间复杂度通常较高(O(n^2)、O(nk)等)通常较低(O(n log n)等)
结果可以得到最优解可能得到最优解,也可能是近似解

5. 总结

  • 动态规划:适用于具有最优子结构和子问题重叠的问题,通过存储子问题的解来避免重复计算,时间复杂度通常较高。
  • 贪心算法:适用于具有贪心选择性质的问题,通常能够以较低的时间复杂度求解问题,但不能保证得到最优解。
  • 动态规划与贪心算法的选择:在实际应用中,需要根据问题的具体性质选择合适的算法。

📢 下一篇 Python学习算法系列(8):回溯算法与分治算法,敬请期待!🚀

💡 如果你喜欢这篇文章,欢迎点赞、收藏,并关注本系列!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值