问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

算法设计中的DP:从斐波那契数列到背包问题

创作时间:
作者:
@小白创作中心

算法设计中的DP:从斐波那契数列到背包问题

引用
CSDN
11
来源
1.
https://blog.csdn.net/m0_73379721/article/details/136765215
2.
https://cloud.baidu.com/article/2899411
3.
https://blog.csdn.net/2403_82497315/article/details/144010902
4.
https://cloud.baidu.com/article/2899377
5.
https://blog.csdn.net/www_tlj/article/details/139033599
6.
https://blog.csdn.net/2302_82116250/article/details/145089634
7.
https://leetcode.cn/problems/fei-bo-na-qi-shu-lie-lcof/solutions/
8.
https://programmercarl.com/%E5%89%8D%E5%BA%8F/%E9%80%92%E5%BD%92%E7%AE%97%E6%B3%95%E7%9A%84%E6%97%B6%E9%97%B4%E4%B8%8E%E7%A9%BA%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6%E5%88%86%E6%9E%90.html
9.
https://www.cnblogs.com/haohai9309/p/18415462
10.
https://leetcode.cn/problems/three-steps-problem-lcci/
11.
https://www.cnblogs.com/Macw07/p/18590285

在算法设计中,动态规划(Dynamic Programming,简称DP)是一种强大的工具,用于解决具有重叠子问题和最优子结构的复杂问题。本文将通过经典的斐波那契数列示例,深入浅出地讲解DP的核心思想和具体应用。

01

斐波那契数列的困境

斐波那契数列是一个经典的递归问题,其定义如下:

直接使用递归实现的代码如下:

def fib(n):
    if n <= 1:
        return n
    else:
        return fib(n-1) + fib(n-2)

然而,这种递归实现存在严重的效率问题。以计算fib(5)为例,其递归调用树如下:

可以看到,许多子问题被重复计算多次,例如fib(2)被计算了3次,fib(1)被计算了5次。这种重复计算导致算法的时间复杂度高达O(2^n),随着n的增大,计算时间将呈指数级增长。

02

动态规划的核心思想

动态规划正是为了解决这类重复计算问题而诞生的。其核心思想是将问题分解为若干个子问题,并从子问题的最优解中寻找原问题的最优解。动态规划的三大基本要素包括:

  1. 最优子结构:每个阶段的最优状态可从之前某个阶段的某个或某些状态直接得到。
  2. 边界:问题最小子集的解,通常是递归的终止条件。
  3. 状态转移函数:描述了两个相邻子问题之间的关系,是动态规划中最关键的部分。
03

优化方法:记忆化搜索与制表法

针对斐波那契数列的重复计算问题,动态规划提供了两种主要的优化方法:记忆化搜索和制表法。

记忆化搜索

记忆化搜索是在递归的基础上,添加一个“记忆”功能,将已经计算过的子问题结果保存起来,避免重复计算。具体实现如下:

def fib_memo(n, memo={}):
    if n <= 1:
        return n
    if n not in memo:
        memo[n] = fib_memo(n-1) + fib_memo(n-2)
    return memo[n]

通过引入memo字典存储已计算的结果,我们可以将时间复杂度降低到O(n)。

制表法(递推)

制表法则是从最小子问题开始,逐步构建更大的子问题的解,最终得到原问题的解。这种方法也称为递推或迭代。具体实现如下:

def fib_dp(n):
    if n <= 1:
        return n
    dp = [0] * (n+1)
    dp[1] = 1
    for i in range(2, n+1):
        dp[i] = dp[i-1] + dp[i-2]
    return dp[n]

同样,这种方法的时间复杂度也是O(n),但相比记忆化搜索,它不需要额外的函数调用开销,因此在实际应用中可能更高效。

04

经典应用:背包问题

动态规划不仅适用于斐波那契数列这样的简单问题,更广泛应用于各种复杂的优化问题。以0-1背包问题为例,给定一组物品,每种物品都有自己的重量和价值,目标是在不超过背包容量的情况下,选择物品使得总价值最大。

这个问题可以通过动态规划来解决。我们定义一个二维数组dp,其中dp[i][j]表示在考虑前i个物品且背包容量为j的情况下能够获得的最大价值。状态转移方程为:

最终答案存储在dp[n][V]中,其中n是物品的数量,V是背包的容量。

05

总结

动态规划是一种强大的算法设计技术,特别适用于解决具有重叠子问题和最优子结构性质的问题。通过记忆化搜索和制表法两种优化手段,可以显著提高算法效率,避免重复计算。在实际应用中,动态规划被广泛用于解决背包问题、最长公共子序列、最短路径等问题。

然而,动态规划并非万能钥匙。它要求问题具有最优子结构和重叠子问题的特性,且设计状态转移方程往往需要一定的技巧和经验。但一旦掌握,它将成为你算法工具箱中不可或缺的利器。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号