零钱兑换Ⅱ

518. 零钱兑换 II - 力扣(LeetCode)

给你一个整数数组 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

解题思路

动态规划

完全背包问题的组合问题,即每个元素都可以重复利用,直到装满背包共有多少种组合

1.确定dp数组及下标的含义

dp[j] 表示 凑成总金额为 j 共有多少种组合

2.确定递推公式

若不考虑coins[i], 装满容量 j - coins[i]背包,有dp[ j - coins[i] ]种方法,

如果把coins[i]装入正好装满容量为j的背包,凑成dp[j]就有dp[ j - coins[i] ]种方法

故递推公式为**dp[j] += dp[ j - coins[i] ]**,表示加入了物品coins[i]之后dp[j]新增了多少种方法,即凑成总金额为 j 新增的方法

3.初始化dp数组

dp[0] = 1,背包容量为0有一种方法,表示什么都不放,该值必须初始化为1,否则无法递推下去

4.确定遍历顺序

本题求的是组合数,先遍历物品,再遍历背包,完全背包问题背包容量从小到大遍历

(如果是求排列数,就要先遍历背包,在遍历物品)

举例:

输入:amount=5,coins = {1,2,5}

dp数组的状态如图

image-20220605005733175

代码

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount+1];
dp[0] = 1; //必须为1,否则无法求组和
for(int i = 0 ; i < coins.length; i++){//遍历物品
for(int j = coins[i]; j <= amount; j++){//遍历背包
dp[j] += dp[j - coins[i]];//
}
}
return dp[amount];
}
}
  • 时间复杂度:$O(n × m)$,n为数组coins大小,m为amount

  • 空间复杂度:$O(m)$


零钱兑换Ⅱ
http://example.com/2023/01/22/算法/动态规划/14. 零钱兑换 II/
作者
PALE13
发布于
2023年1月22日
许可协议