322. 零钱兑换
动态规划-自顶向下
- 定义 要凑出金额n 至少要dp(coins,n)个硬币
- 确定base case 目标金额为0 返回0
- 确定 状态 也就是原问题和子问题中的变量,你每次抽取一个硬币,都会导致目标金额减少,所以状态就是目标金额
- 确定选择,也就是导致状态产生变化的行为,每次选一个硬币都会导致目标金额的减少
- 明确dp数组的定义,状态数组的每一个值都是代表目标金额
class Solution {
int[] memo;
public int coinChange(int[] coins, int amount) {
memo = new int[amount + 1];
Arrays.fill(memo,-666);
return dp(coins,amount);
}
int dp(int[] coins,int amount){
if(amount == 0){
return 0;
}
if(amount < 0){
return -1;
}
if(memo[amount] != -666){
return memo[amount];
}
int res = Integer.MAX_VALUE;
for(int coin: coins){
int sub = dp(coins,amount - coin);
if(sub == -1){
continue;
}
res = Math.min(res,sub + 1);
}
memo[amount] = (res == Integer.MAX_VALUE) ? -1:res;
return res == Integer.MAX_VALUE ? -1:res;
}
}
动态规划-自底向上
- 状态数组的每一个状态都是代表目标金额
- 外层for循环遍历所有状态的所有取值
- 内层for循环遍历所有状态的所有取值
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp,amount + 1);
dp[0] = 0;
for(int i = 0; i < dp.length; i++){
for(int coin:coins){
if(i - coin < 0){
continue;
}
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
return (dp[amount] == amount + 1) ? -1 : dp[amount];
}
}