零钱兑换: II -完全背包

73 阅读1分钟

518. 零钱兑换 II

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

思路

  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];
};