动态规划算法学习

1 动态规划题目类型

动态规划题目类型

2 动态规划解题步骤(例题:Coin Change)

Coin Change问题描述:

  1. 你有三种硬币(2、5、7),每种数量无穷多
  2. 你去书店买一本27元的书,老板无零钱,你需要刚好付27元
  3. 你支付的硬币个数最少是多少个?

注意:由于问题中涉及“最少”,因此考虑使用动态规划求解

2.1 确定状态

2.1.1 最后一步

假设最优策略:a1, a2, …, ak
最后一步就是对ak的决策(取2/ 5/ 7)
因此,a1, a2, …, ak-1拼出了27 - ak,这也是最优策略
为什么也是最优策略?
反证法:

  1. 若仅用k - 2枚硬币即可拼出27 - ak(即a1, a2, …, ak-1拼出27 - ak不是最优策略)
  2. 则拼出27仅需k - 1枚硬币,与最优策略k枚硬币矛盾
  3. 因此,是最优策略

2.1.2 子问题

由上述最后一步的分析,可以得到子问题的描述:求最少使用多少枚硬币能拼出27 - ak
原问题:求最少使用多少枚硬币能拼出27?

由此可以确定状态:f(X) = 最少用多少枚硬币能拼出X

2.2 确定状态转移方程

分析:
由上述“最后一步”和“子问题”的分析,我们可以很容易得到下列公式:
f(27) = min{f(27 - 2) + 1, f(27 - 5) + 1, f(27 - 7) + 1}

  1. ak = 2,子问题为:最少多少枚硬币能拼出25?
  2. ak = 5,子问题为:最少多少枚硬币能拼出22?
  3. ak = 7,子问题为:最少多少枚硬币能拼出20?

由此得到状态转移方程:
f[X] = min{f[X - 2] + 1, f[X - 5] + 1, f[X - 7] + 1}

2.3 确定初始条件和边界情况

思考:如果X-2 / X- 5 / X - 7小于0怎么办?
初始条件:f[0] = 0
边界情况:f[-1] = f[-2] = … = 正无穷
边界情况设置的原因为:避免数组越界

2.4 确定计算顺序

由上述初始条件、边界情况和状态转移方程可知:该例题的计算顺序为正向(从左往右、从小到大)计算
因为:计算f[X]时,f[X - 2],f[X - 5],f[X - 7]已经得到结果了

3 例题求解

3.1 递归算法求解

def solve_coin_change(X):
    """拼出X最少需要多少枚硬币"""
    if X == 0:
        return 0
    min_num = float('inf')
    if X >= 2:
        min_num = min(solve_coin_change(X - 2) + 1, min_num)
    if X >= 5:
        min_num = min(solve_coin_change(X - 5) + 1, min_num)
    if X >= 7:
        min_num = min(solve_coin_change(X - 7) + 1, min_num)
    return min_num
    
solve_coin_change(27)  # 结果为5

递归树:可以发现存在大量重复计算,导致时间复杂度为指数级别,性能很差
在这里插入图片描述

3.2 图示动态规划计算过程

在这里插入图片描述

3.3 动态规划代码

def solve_coin_change(X):
    """拼出X最少需要多少枚硬币"""
    # 设置初始条件和边界情况
    dp = [0]  # dp[0] = 0
    if X < 0:
        return float('inf')

    # 计算动态规划数组dp
    for i in range(1, X + 1):
        if i < 2:
            dp.append(float('inf'))
        elif i < 5:
            dp.append(min(dp[i - 2] + 1, float('inf')))
        elif i < 7:
            dp.append(min(dp[i - 2] + 1, dp[i - 5] + 1, float('inf')))
        else:
            dp.append(min(dp[i - 2] + 1, dp[i - 5] + 1, dp[i - 7] + 1))

    # 返回结果
    return dp[X]

solve_coin_change(27)  # 结果为5

3.4 动态规划时间复杂度分析

设有m种硬币,需要拼出n:
需要循环计算n次动态规划数组,每一次计算将每种硬币的选取均考虑了一次,因此时间复杂度为O(m x n)

4 常考动态规划类型

在这里插入图片描述

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值