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

518. 零钱兑换Ⅱ

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

思路

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

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状态图如下:

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

代码实现

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]

你可能感兴趣的:(代码随想录训练营,算法,动态规划,python,leetcode)