Leetcode每日一题——518.零钱兑换。动态规划。多重背包应用。多重背包与排列组合的关系

题目链接:

力扣

题目描述:

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。 

题目数据保证结果符合 32 位带符号整数。

示例 1:

输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
示例 2:

输入:amount = 3, coins = [2]
输出:0
解释:只用面额 2 的硬币不能凑成总金额 3 。
示例 3:

输入:amount = 10, coins = [10] 
输出:1
 

提示:

1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins 中的所有值 互不相同
0 <= amount <= 5000

解析:

题目要求从coins数组中选出一些元素放入背包中,且这些元素满足一定的条件(凑成amount),这种

思路满足背包问题。由于每种硬币数量无限,所以是多重背包问题。

与多重背包的对应关系:coins[i]相当于物品,amount相相当于背包容量,价值相当于组合数量

递归四部曲:

确定dp数组:dp[j]表示凑成j的硬币组合数量

确定递推公式:dp[j] = dp[j] + dp[j - coins[i]],因为求得是组合的数量,所以dp值是累加,而不是取最大值,因为取得是所有情况而不是特定的某种情况

初始化dp数组:dp[0] = 1意义是凑成0的情况只有一种,即什么都不取

确定遍历顺序:求组合的数量的话就先遍历物品再遍历容量,均采用顺序遍历

代码如下:

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        dp = [0] * (amount + 1)
        dp[0] = 1
        for i in range(len(coins)):
            for j in range(coins[i], amount + 1):
                dp[j] += dp[j - coins[i]]
        return dp[amount]

这里说一下求组合数量得先遍历物品再遍历容量的原因:

假设dp[0]=1,dp[1]=3。那么先遍历物品再遍历容量的话就只能先到取1,再取3,只能取到{1, 3}这个组合,而不能取到{3, 1}这个组合。即dp[4]中对于1和3就只有{1, 3}这种情况

再说一下求排列数量得先遍历容量再遍历容物品的原因:

假设dp[0]=1,dp[1]=3。那么先遍历容量再遍历物品的话每个容量都要经过1和3的计算,即会先对取1的情况进行决策(可以取到{1, 3}),再对取3的情况进行决策(可以取到{3, 1})。即dp[4]中对于1和3有{1, 3}和{3, 1}2种情况.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翔空中,策人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值