【动态规划】322. 零钱兑换

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];
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少写代码少看论文多多睡觉

求打赏,求关注,求点赞

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值