零钱兑换 II
问题描述
给定不同面额的硬币和一个总金额,写一个函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
问题分析
这是一个典型的动态规划问题。我们可以使用动态规划来解决这个问题。具体来说,我们可以使用一个一维数组dp来记录目标金额为i时的硬币组合数。数组dp的长度为目标金额加一,初始时所有元素都为零。然后,我们遍历硬币的面额,对于每个面额coin,我们从coin开始遍历到目标金额amount,并更新dp[j]的值。更新的逻辑是,对于每个j,dp[j]的值等于dp[j]和dp[j-coin]之和,其中dp[j-coin]表示使用硬币coin时的组合数,dp[j]表示不使用硬币coin时的组合数。最终,返回dp[amount]即可。
算法实现
下面是整个算法的流程图:
| 步骤 | 动作 |
|---|---|
| 1 | 初始化dp数组,将所有元素设置为零。 |
| 2 | 对于每个硬币面额coin,执行以下步骤: |
| 3 | 对于i从coin到目标金额amount,执行以下步骤: |
| 4 | 更新dp[i]的值为dp[i] + dp[i-coin]。 |
| 5 | 返回dp[amount]的值。 |
下面是具体的代码实现:
public int change(int amount, int[] coins) {
// 初始化dp数组
int[] dp = new int[amount + 1];
dp[0] = 1;
// 遍历硬币面额
for (int coin : coins) {
// 遍历目标金额
for (int i = coin; i <= amount; i++) {
// 更新dp[i]的值
dp[i] += dp[i - coin];
}
}
// 返回dp[amount]的值
return dp[amount];
}
代码解析
首先,在算法的开始部分,我们初始化了一个一维数组dp,将所有元素都设置为零。数组的长度为目标金额amount加一,这是因为我们需要考虑目标金额为零的情况。然后,我们将dp[0]的值设置为1,表示当目标金额为零时,存在一种硬币组合方式,即不使用任何硬币。
接下来,我们使用两个嵌套的循环来遍历硬币的面额和目标金额。外层循环遍历硬币面额coin,内层循环从coin开始遍历到目标金额amount,并更新dp[i]的值。更新的逻辑是,我们将dp[i]的值加上dp[i-coin]的值,表示使用硬币coin时的组合数。
最后,我们返回dp[amount]的值,即为目标金额amount的硬币组合数。
总结
通过动态规划算法,我们可以高效地计算出给定金额的硬币组合数。这个算法的时间复杂度为O(amount * n),其中,amount为目标金额,n为硬币的面额个数。通过使用动态规划算法,我们可以避免重复计算,从而提高了算法的效率。










