518. 零钱兑换 II(完全背包一维二维的理解)
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了518. 零钱兑换 II(完全背包一维二维的理解)相关的知识,希望对你有一定的参考价值。
518. 零钱兑换 II
2021.6.10每日一题,完全背包一维二维的理解
题目描述
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
示例 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change-2
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
一个硬币可以使用多次,完全背包问题
dp[i]表示可以组成面额为i的组合的个数
外层循环遍历coins中的值,内层循环遍历金额总数,在计算 dp[i] 的值时,可以确保金额之和等于 i 的硬币面额的顺序,由于顺序确定,因此不会重复计算不同的排列。例如对于金额3,因为硬币值的顺序是固定的,因此先1后2,只有一种情况
而如果两层循环反过来了,就是求排列数,因为第一层循环是遍历金额,第二层循环是遍历硬币,例如对于3这个金额,你可以在1后面选择2,也可以在2后面选择1,就是两种情况
class Solution {
public int change(int amount, int[] coins) {
//完全背包,每个物品可以使用无限次
//想想,一维,正序遍历
int l = coins.length;
int[] dp = new int[amount + 1];
//初始化,总金额为0的时候,有一种方式
dp[0] = 1;
for(int i = 0; i < l; i++){
for(int j = 0; j <= amount; j++){
if(j >= coins[i])
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}
变成二维的,代码如下:
这里有个与平时二维dp不同的一点,就是当面额大于等于当前硬币值的时候,需要加的不是dp[i - 1][j - coins[i - 1]],而是加的是dp[i][j - coins[i - 1]],
这个点怎么理解呢,我认为是因为一个硬币可以使用多次,而不是0-1背包中只能使用一次了,因此之前使用过这个硬币了,现在还可以继续使用。因此要从dp[i]来转移
class Solution {
public int change(int amount, int[] coins) {
//写个二维的,再品一品
int l = coins.length;
int[][] dp = new int[l + 1][amount + 1];
//初始化,总金额为0的时候,有一种方式
for(int i = 0; i <= l; i++){
dp[i][0] = 1;
}
for(int i = 1; i <= l; i++){
for(int j = 1; j <= amount; j++){
dp[i][j] = dp[i - 1][j];
if(j >= coins[i - 1])
dp[i][j] += dp[i][j - coins[i - 1]];
}
}
return dp[l][amount];
}
}
再看三叶姐写的二维的,这种二维的更好理解,每个都硬币使用无数次,所以遍历每个硬币使用的情况
class Solution {
public int change(int cnt, int[] cs) {
int n = cs.length;
int[][] f = new int[n + 1][cnt + 1];
f[0][0] = 1;
for (int i = 1; i <= n; i++) {
int val = cs[i - 1];
for (int j = 0; j <= cnt; j++) {
f[i][j] = f[i - 1][j];
for (int k = 1; k * val <= j; k++) {
f[i][j] += f[i - 1][j - k * val];
}
}
}
return f[n][cnt];
}
}
作者:AC_OIer
链接:https://leetcode-cn.com/problems/coin-change-2/solution/gong-shui-san-xie-xiang-jie-wan-quan-bei-6hxv/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
完全背包二维变成一维的,还是比较难理解的,很多题解都是之直接变过来了,最多写一下一维的dp数组遍历的过程,严格证明的几乎没有
三叶姐是看到的第一个证明为什么将01背包时dp一维数组遍历顺序反过来就变成了完全背包,学习一下:
https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&mid=2247486107&idx=1&sn=e5fa523008fc5588737b7ed801caf4c3&chksm=fd9ca184caeb28926959c0987208a3932ed9c965267ed366b5b82a6fc16d42f1ff40c29db5f1&token=660810714&lang=zh_CN#rd
以上是关于518. 零钱兑换 II(完全背包一维二维的理解)的主要内容,如果未能解决你的问题,请参考以下文章
[M背包] lc518. 零钱兑换 II(完全背包+背包求方案数)
算法---- 01背包问题和完全背包问题LeetCode系列问题题解
算法---- 01背包问题和完全背包问题LeetCode系列问题题解