(算法理论)动态规划(python)

本文详细介绍了动态规划的基本思想、与分治法的区别、解决问题的步骤,并通过多个实例,如连续子数组最大和、数字和为sum的方法数、最长上升子数列、零钱兑换、0-1背包问题,探讨了动态规划的自底向上求解策略,并提供了Python代码实现。动态规划通过记忆化存储避免重复计算,以提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态规划

基本思想

若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用

明确三个事情:

  1. 目标问题
  2. 状态的定义:opt[n]
  3. 状态转移方程:opt[n]=best_of(opt[n-1],opt[n-2])

分治与动态规划

共同点:二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决的程序)的子问题.然后将子问题的解合并,形成原问题的解.

不同点:分治法将分解后的子问题看成相互独立的,通过用递归来做。
动态规划将分解后的子问题理解为相互间有联系,有重叠部分,需要记忆,通常用迭代来做。

步骤

  1. 求一个问题的最优解
  2. 大问题可以分解为子问题,子问题还有重叠的更小的子问题
  3. 整体问题最优解取决于子问题的最优解(状态转移方程)
  4. 从上往下分析问题,从下往上解决问题
  5. 讨论底层的边界问题

动态规划最重要的有三个概念:1、最优子结构 2、边界 3、状态转移方程

引出:

由一个简单的问题来解释为什么要使用动态规划:
有十个台阶,从上往下走,一次只能走一个或两个台阶,请问总共有多少种走法?

  1. 最优子结构:我们来考虑要走到第十个台阶的最后一步,最后一步必须走到第八或者第九。不难得到 f(10) = f(9)+f(8)、f(9) = f(8)+f(7)·····
  2. 边界:f(1) = 1, f(2) = 2
  3. 状态转移:f(n) = f(n-1) + f(n-2)

简单粗暴的递归解法:

def get_count(n):
    if n == 1:return 1
    if n == 2:return 2
    else:
        return get_count(n-1)+get_count(n-2)
print(get_count(10))

在这里插入图片描述
很显然这是一个满二叉树,高度为N-1。所以总节点数为2N−12^{N-1}2N1,时间复杂度为O(2N2^{N}2N) 。看着就恐怖。递归计算方法,我们不难看出,2N−12^{N-1}2N1个节点产生了大量重复的运算。找到问题的根源,对应的解决方法就应运而生,那就是从下往上算,把以前计算过的数值,保存在一个哈希表中,然后后面计算时先查询一下,存在就无需计算。时间复杂度为O(n) ,空间复杂度为O(n)。但是在仔细一想其实,无需保存所有的fff,每个fff

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值