给你一个整数数组 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
思路
- 其实就是化归为01背包,先去遍历物品,dp[i][j] 代表的是从0-i选择 i 个硬币,然后凑价值为j有几种方法,初始化 dp[0][0] =1;
/**
* @param {number} amount
* @param {number[]} coins
* @return {number}
*/
var change = function(amount, coins) {
// 初始化dp数组,行数为硬币数量加1(包括0个硬币的情况),列数为amount+1
let dp = new Array(coins.length + 1).fill(null).map(() => new Array(amount + 1).fill(0));
// 初始化第一列,对于任意数量的硬币,凑成0金额的方法有1种(即不选任何硬币)
for (let i = 0; i < coins.length + 1; i++) {
dp[i][0] = 1;
}
// 遍历硬币数量
for (let i = 1; i <=coins.length; i++) {
// 遍历金额
for (let j = 1; j <= amount; j++) {
// 如果当前金额大于等于硬币面额,则加上包含该硬币的情况
if (j >= coins[i - 1]) {
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i-1]];
} else {
// 如果金额不足以使用当前硬币,则继承上一行的状态
dp[i][j] = dp[i - 1][j];
}
}
}
// 返回最终结果,即用所有硬币凑成amount的方法数
return dp[coins.length][amount];
};