血战力扣 332.零钱兑换

题目:

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。你可以认为每种硬币的数量是无限的。

 解答:这里我们以第一个示例演示,分别画出每种金额的树形结构,如下

 这里我们采取一种自下而上的方法,这里我重点解释代码中一个公式:

dp[i]=min(dp[i],dp[i-e]+1);

dp[i]:表示不同的金额下所需最少的钱币数

dp[i-e]+1:这里i-e表示当前金额减去一种面值后金额,dp[i-e]的值一定代表i-e时所需要的最小的钱币数这个值我们之前一定算过,因为最开始就是从金额是0开始递增来计算不同金额所需的最小钱币数,这里的e表示不同的面值的大小,正因为我们减去了一枚钱币,所以后面要加个1,所以dp[i-e]+1表示的就是当前所耗费的钱币数啊!!!

dp[]是一个数组,并且数组里的值都被表示为很大的数,dp[i-e]+1表示钱币数一定会代替当前的dp[i],没错吧,之后我们计算每个dp[i-e]+1的数量,将最小的保存下来就可以啦!最后在计算大一个金额的,以此类推。

可以结合上面的树形图去观察,会发现每个树杈下面都是之前算过的,其实就是在遍历每个树杈子,例如 计算amount =4时,我们直接就比较3 和 2所用的钱币数就可以啦(其实就是dp[2]和dp[3]),不用重复计算,这就是自下而上的好处!!

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        if(amount==0) return 0;
        int dp[10005];
        for(auto& i: dp) i=10006;
        dp[0] = 0;
       //这一步求出我们要计算金额之前每种金额需要的最少钱币数
        for(int i=0; i<=amount; i++) {
             //这里是遍历每个硬币的面值
            for(auto& e: coins) {
                //用总金额-硬币面值
                if(i-e>=0) 
              
                    dp[i]=min(dp[i],dp[i-e]+1);
            }
        }
        return dp[amount]>=10006? -1: dp[amount];
    }

};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值