每日一题之零钱兑换

2020-05-01  本文已影响0人  this_is_for_u

题目322:零钱兑换

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例1:

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

示例2:

输入: coins = [2], amount = 3
输出: -1

说明:

你可以认为每种硬币的数量是无限的。

分析

这题可以用贪心也可以用dp,这里使用dp方式,以示例1举例,如下图,有硬币[1, 2, 5],想要组成11,那就需要先组成(11-1, 11-2, 11-5),即(10, 9, 6),括号内为或关系,就是说想要组成11,那就需要先组成10或9或6,这里用dp存储组成x需要的硬币个数,则dp[11]= min(dp[10], dp[9], dp[6])+1,依此类推,dp[10] = min(dp[10-1], dp[10-2], dp[10-5]) + 1,这是从上向下类推,基本上从上向下类推的规律都可以从下向上推导,具体可以看代码啦。

代码

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        if (amount == 0) return 0;
        // 如果没有任何一种硬币组合能组成总金额,返回 -1
        const int fail_value = -1;
        vector<int> dp(amount + 1, fail_value);
        std::sort(coins.begin(), coins.end());
        for (int i = 1; i <= amount; ++i) {
            for (auto coin : coins) {
                if (i == coin) {
                    dp[i] = 1;
                    break;
                }
                if (i < coin) {
                    break;
                }
                if (dp[i-coin] != fail_value) {
                    if (dp[i] == fail_value) {
                        dp[i] = dp[i-coin] + 1;
                    } else {
                        dp[i] = min(dp[i-coin] + 1, dp[i]);
                    }
                }
            }
        }
        return dp[amount];
    }
};

更多文章请关注公众号

programmersmall.png
上一篇下一篇

猜你喜欢

热点阅读