代码随想录算法训练营第五十天(完全背包篇)|518. 零钱兑换Ⅱ

本文介绍了如何使用动态规划解决零钱兑换问题,将问题转化为完全背包类型,通过定义dp数组并应用递推公式计算装满容量的组合方法,强调了外层遍历物体、内层遍历容量的重要性。代码实例展示了如何在给定金额和零钱面值的情况下计算可能的组合方式。

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

518. 零钱兑换Ⅱ

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路

本题相当于求装满容量为amount的背包有多少种方法,又由于零钱可以重复使用,属于完全背包的题型。将01背包完全装满的思路在494. 目标和中介绍过,在完全背包的理论基础中,知道它与01背包的接替区别只在于遍历顺序,因此此题很容易便能写出。代码随想录算法训练营第四十八天(动态规划篇之01背包)| 1049. 最后一块石头的重量Ⅱ,494. 目标和-优快云博客代码随想录算法训练营第四十九天(动态规划篇)| 474. 一和零, 完全背包理论基础-优快云博客

1. dp数组定义

dp[j]:装满容量为j的完全背包有dp[j]种方法。

2. 递推公式

对于面值为i的零钱,它和之前遍历过的零钱凑成总金额amount的方法取决于之前的硬币能凑成总金额(amount-i)的方法,把这个零钱i能凑成的方法加入到dp[j]中。因此,递推公式为:

dp[j] += dp[amount - i]

3. 初始条件

dp[0]要为1,如果是0,那么之后递推出来的dp值都为0。dp[0] = 1可以认为凑成零就是不拿出任何零钱这一种方法。dp[0]=1还说明了一种情况:如果正好选了面值为j的零钱,也就是j-coins[i] == 0的情况,表示这个硬币刚好能选,此时dp[0]为1表示只选coins[i]存在这样的一种选法。其他下标的dp值保持为0就可。

4. 遍历顺序

对完全背包求总和的最大价值,容量从小到大遍历,可以外层遍历物体,内层遍历容量,也可以外层遍历容量,内层便遍历物体,和凑成总和的元素有没有顺序没关系。但对于这道题,我们要求凑成总和的元素是无序的,即{1,4}和{4,1}都能凑成5,但它们是一种方法,而非两种。分别考虑两种遍历顺序

1. 外层遍历容量,内层遍历物体

如果先遍历容量,再遍历物体,对当前容量,假设遍历第一个物体,发现与第三个物体能凑成总和,方法数加了1,那继续遍历到第三个物体时,又发现能与第一个物体凑成,方法数又加了1,就重复了。

2. 外层遍历物体,内层遍历容量

如果先遍历物体,再遍历容量,就是先把第一个物体加入运算,那时第三个物体还没加入,所以没有凑成,等遍历到第三个物体时,才能和第一个物体凑成,不会造成重复。

因此,应该外层遍历物体,内层遍历容量。

5. 举例推导dp数组

输入: amount = 5, coins = [1, 2, 5] ,dp状态图如下:

代码实现

class Solution(object):
    def change(self, amount, coins):
        dp = [0]*(amount + 1)
        dp[0] = 1
        for coin in coins: 
            for j in range(coin, amount + 1):
                dp[j] += dp[j-coin]
        return dp[amount]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值