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);// 初始化一个特殊值 表示还没有计算
// 题目要求的最终结果就是dp
return dp(coins,amount);
}
// 定义 要凑出金额n 至少要dp(coins,n)个硬币
// dp状态是 变化的 也就是原问题和子问题的变量 由于硬币数量无限,仔细想一下 你每次抽取一个硬币 变化的是什么 目标总金额 抽取硬币的次数就是状态数组的长度 每次抽取 状态变量都会变化
int dp(int[] coins,int amount){
// base case
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];
// 数组大小是 amount + 1
int[] dp = new int[amount + 1];
Arrays.fill(dp,amount + 1);
// base case
dp[0] = 0;
// 外层for循环在遍历所有状态的所有取值 每一个状态都是目标金额
for(int i = 0; i < dp.length; i++){
// 内层for循环遍历所有状态的所忧取值
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];
}
}
文章来源地址https://www.toymoban.com/news/detail-691594.html
文章来源:https://www.toymoban.com/news/detail-691594.html
到了这里,关于【动态规划】322. 零钱兑换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!