题目
动态规划
public int change(int amount, int[] coins) {
if (amount == 0) {
return 0;
}
// dp[i][j]代表选择了前i种硬币, 能装满j的种数
int [][] dp = new int[coins.length + 1][amount + 1];
// base case 目标金额为0, 那么不管给多少硬币, 只有一种装法 即[]
for (int i = 0; i <= coins.length; i ++) {
dp[i][0] = 1;
}
for (int i = 1; i <= coins.length; i ++) {
for (int j = 1; j <= amount; j ++) {
if (j - coins[i - 1] >= 0) {
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[coins.length][amount];
}
思路
(1) 按照背包问题去理解, 因此一定是个二维dp数组, 硬币的种类是i, 目标金额就是背包空间的大小, dp[i][j] 就是选择前i种硬币, 填满j大小的背包一共有多少种可能
(2) 注意base case, 背包大小为0的时候, 装满背包的方案只有一种, 那就是不装.
(3) 既然是必须恰好装满背包, 那判断条件为啥是j - coins[i - 1] >= 0呢? 而不是j - coins[i - 1] == 0呢? 因为是这样的, 当前的硬币值是coins[i - 1], 那么就假设当前背包是空的, 能否放下这个硬币, 而不是说背包已经装的只差这枚硬币了, 因此是 >= 0, 而不是 ==0;
当j - coins[i - 1] > 0 的时候, 说明可以放下这枚硬币, 到底放下之后能不能凑满整个背包, 就是由dp[i, j - coins[i - 1]]决定的了.
(4) 为啥状态转移方程是 dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]];
因为可以放, 但是不放, 是一种情况, 放了, 是另一种情况, 答案应该是这两种情况的次数相加