LeetCode 零钱兑换 II(518题)完全背包转换

LeetCode 零钱兑换 II

@author:Jingdai
@date:2021.09.12

题目描述(518题)

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

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

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

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

示例输入

amount = 5, coins = [1, 2, 5]

示例输出

4

解释

解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

思路及代码

这个题目是典型完全背包问题,看了很多题解,都没有说明白这个题目是如何转换为完全背包的,所以本文将会从完全背包一步步推导到最简的式子。后面的讲解需要有一点点01背包和完全背包的知识,这里不再讲这些基础。

把题目中的 amount 看成容量,coin 看成物品,物品的重量和价值都是 coin 值。那么这个题目就是求完全背包的方案数,同时,题目要求完全背包必须装满的方案数。和完全背包一样,用一个 dp 记录最大的价值,由于还需要记录方案数,所以用第二个数组 dp2 记录方案数。

初始化,对于没有装满的背包,这是一个无效状态,dp 中的值我们初始化为负无穷大,而 dp2 中的值为0。对于dp[0] ,背包容量为0,0件物品,相当于装满了,是有效状态即 dp[0] 初始化为0。而对于 dp2,dp2[0] 容量为0,0件物品,装满了,即有一个方案,所以初始化为1。

递推,dp 数组的更新和完全背包一样,主要看 dp2 数组的更新。wi 代表第 i 件物品重量,vi 代表第 i 物品价值,在本题中都一样,都是 coin 的值。

当 dp[j-wi] + vi > dp[j] 时,dp[j] = dp[j-wi] + vi。dp2呢?因为它从j-wi更新过来,所以也应该更新为这个,即 dp2[j] = dp2[j-wi]。

当 dp[j-wi] + vi = dp[j] 时,dp[j] 就不用更新了,但是 dp2 还是要更新,因为它多了从 j-wi 转移过来的方案,所以dp2[j] += dp2[j-wi]。

当 dp[j-wi] + vi < dp[j] 时,dp[j] 不用更新,同时方案数也没有变,所以 dp2[j] 也不用更新。

根据此,就可以完成如下代码。

public int change(int amount, int[] coins) {
   

    if (amount == 0) {
   
        return 1;
    }

    int n = coins.length;
    int
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值