零钱兑换问题

518. 零钱兑换 II - 力扣(LeetCode)

        算法小菜鸡学习ing

        一道很简单的dp动态规划的问题,没想到居然还翻了跟头卡了好久,错误的原因是最初内外层的循环写反了(其实是dp的思路有些问题)。
        如果是先遍历所有金额再遍历硬币的数量,在便利过程中你会发现有些amount的dp值会有重复的情况。举个例子:

输入:amount = 5, coins = [1, 2, 5]
输出:4

按照我先遍历amount后遍历coins的情况下:

dp[5]+=dp[5-5];
dp[5]+=dp[4];
dp[5]+=dp[3]

dp[4]中有  +1
1+1+1+1
1+2+1
2+2

dp[3]中有  +2
1+2
1+1+1

这样下来再加上新加入的硬币,就会产生两个重复情况

 当交换了内外层循环后:

  1. 避免重复计算:

    • 当外层循环遍历硬币面额时,内层循环遍历金额 amount。这意味着对于每个硬币面额,内层循环会在其对应的金额范围内更新 dp 数组。因为在计算某个金额时,只考虑当前硬币面额及之前的硬币面额,而不会考虑后面的硬币面额。这样确保了每个组合只被计算一次,避免了重复计算。
  2. 确定 dp 数组的初始值:

    • 在动态规划中,通常需要一个初始值来开始计算。对于这个问题,初始值是确保凑齐金额为 0 的硬币组合数为 1。这是因为如果金额为 0,那么不需要任何硬币就可以凑齐,因此硬币组合数为 1。
    • 因此,将 dp[0] 设置为 1 是合理的初始值。
  3. 下面是正确的代码
class Solution {
public:
    int dp[10000];
    int change(int amount, vector<int>& coins) {
        int ans=0;
        sort(coins.begin(),coins.end());
        dp[0]=1;
        if(amount==0)
            return 1;
        if(amount<coins[0])
            return 0;
        for(int coin:coins){
            for(int i=coin;i<=amount;i++){
                dp[i]+=dp[i-coin];
            }
        }
        return dp[amount];
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值