力扣322.零钱兑换

一.题目:

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。你可以认为每种硬币的数量是无限的。
示例:
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
示例 3:
输入:coins = [1], amount = 0
输出:0

观察示例可以看到,目标和amount == 0时是返回0的,而去其他值如果不能被凑出来就是返回-1.

二.分析:

前面518. 零钱兑换 II和377. 组合总和 Ⅳ都是求组合数或者排列数,都需要累加,这题不需要。这题求凑成总金额所需的 最少的硬币个数

而且这题dp[j]表示取得目标值j所需的最少钱币个数,而不是钱币组合数

1.为什么不用分“取当前还是不取当前”两种情况

因为我们直接递推公式dp[j]的意义就是所需钱币的最少个数,这已经考虑到取还是不取的问题了,能不取当前遍历到的钱币的时候,肯定所需钱币会更少!除非必须取

2.为什么要min,而不是直接dp[j] = dp[j - coins[i]] + 1

每次取最小或者最少个数这种题,一般都要带上min()。

其实对于这道题来说,取min()和上面的说法一样,当我没有取当前钱币的时候,所需钱币不就最少吗,但是我不知道要不要取当前钱币i啊!

举个例子:
coins = [1, 2, 5],target = 5;

首先dp[0] = 0;目标为0肯定不用取任意一个钱币。

dp[1] = dp[1 - coins[0]] + 1,因为coins[1]及往后就比目标1大了,所以dp[1] = dp[1 - 1] + 1= dp[0] + 1 = 1

dp[2] = dp[2 - coins[0]] + 1 ,或dp[2 - coins[1]] + 1 ,coins[2]就不行了,5比目标2大。计算下来,还得是取coins[1]的时候dp[2] = dp[2 -2 ] + 1 = 1,最小

所以,这个min就是在取不同i时,取那个能使得dp[j]最小的情况,可能当前i不取,只取了i - 1之前的

综合1和2,所以递推关系式从选择当前物品i出发,再用取一个min来表示取和不取两种情况。

dp[j] = min(dp[j], dp[j - coins[i]] + 1)

3.遍历循环顺序

因为本题既不是组合又不是排列,所以物品和背包谁在外面里面都无所谓。

此外,完全背包都是从小到大遍历。

三.代码

还有一些细节见代码:

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        //取最小值问题,一般为了防止被覆盖,初值设置为最大整数
        vector<int>dp(amount + 1, INT_MAX);
        dp[0] = 0;//递推初始条件
        for(int i = 0; i < coins.size(); ++i){
            for(int j = coins[i]; j <= amount; ++j){
                if(dp[j - coins[i]] < INT_MAX){ //因为dp[j - coins[i]]可能没有,即也为初值,那后面+1就会溢出
                dp[j] = min(dp[j], dp[j - coins[i]] + 1);
                }
            }
        }
        //如果没有任何一种硬币组合能组成金额,那说明保留的是初始值,没变过,返回-1
        if(dp[amount] == INT_MAX) return -1;
        return dp[amount];  
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值