题干:给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0。
由于这里求的是组合问题,因此这里不能直接套用零钱兑换问题。这里的核心点就是最外层需要对coins数组进行遍历,在第二层循环再对amount遍历,具体解析过程见代码。
package likou;
/*
* 518.零钱兑换Ⅱ
* 题干:给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额
* 请你计算并返回可以凑成总金额的硬币组合数。
* 如果任何硬币组合都无法凑出总金额,返回 0
*
*/
public class Demo518 {
/*
* 如果只是算总共有多少种方法,可以直接用i对金额进行遍历
* for(int i=1;i<=amount;i++){
for (int k = 0; k < length; k++) {
int temp = i-coins[k];
if(temp == 0) {
dp[i] = dp[i] + 1;
}else if(temp > 0) {
dp[i] =dp[i] + dp[temp];
}
}
}
* 但这样会有一个问题,就是会重复计算,例如conins=[1,2,5],amount =3,可以算出dp[3] = 3
* 这里会重复计算如3=1+1+1,3=1+2,3=2+1,出现重复
* 换一种思路:
* 从coins[]维度出发对conins数组进行遍历,依次计算金额m(从coins[i]到amount),
* 计算当次dp[m-coins[i]],然后再累加
* 即dp[i] = dp[i]+dp[m-coins[i]]
* 最后返回dp[amount]即为最终方法数,具体代码见change方法
*/
public int changeNew(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
int length = coins.length;
for(int i=1;i<=amount;i++){
for (int k = 0; k < length; k++) {
int temp = i-coins[k];
if(temp == 0) {
dp[i] = dp[i] + 1;
}else if(temp > 0) {
dp[i] =dp[i] + dp[temp];
}
}
}
return dp[amount];
}
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for(int k=0;k<coins.length;k++){
int coin = coins[k];
for (int i = coin; i <= amount; i++) {
dp[i] =dp[i]+dp[i - coin];
}
}
return dp[amount];
}
public static void main(String args[]) {
Demo518 demo = new Demo518();
int[] coins = {1,2,5};
int amount = 3;
System.out.println(demo.change(amount,coins));
System.out.println(demo.changeNew(amount,coins));
}
}