持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
最近一直在力扣刷题,也逐渐对各类题型有了自己的理解,所谓见招拆招,将自己的浅显经验分享一下,帮助更多在编程路上的朋友们。
零钱兑换Ⅱ
给你一个整数数组 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 <= 3001 <= coins[i] <= 5000coins中的所有值 互不相同0 <= amount <= 5000
思路
题目思路很简单,很普通的动态规划,但是也有一个难点,如果先遍历金额和,后遍历不同金额coins,则会导致重复的计算,对于dp[3]来说,可能的排列是 1 + 1 + 1,或者 1 + 2,但是也会出现 2 + 1 的情况,所以这种做法不能解决重复的情况。
先遍历coins后遍历金额和,不会重复计算不同的排列。因为外层循环是遍历数组 coins 的值,内层循环是遍历不同的金额之和,在计算 dp[i] 的值时,可以确保金额之和等于 i 的硬币面额的顺序,由于顺序确定,因此不会重复计算不同的排列。
一定是先遍历金额1,再遍历金额2,组合中就不会出现 2 + 1 的情况。
题解
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for(int coin: coins) {
for(int i = 1; i <= amount; i++) {
if(i >= coin) {
dp[i] += dp[i - coin];
}
}
}
return dp[amount];
}
}