题目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];
}
};
网友评论