题目链接
题目描述
给定不同面额的硬币 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
示例 4:
输入: coins = [1], amount = 1
输出: 1
示例 5:
输入: coins = [1], amount = 2
输出: 2
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104
解题思路
动态规划
完全背包问题,且必须取到amount值
可设每个面额的权重为1,求最小权重。
转移公式由dp[i] = max(dp[i],1+dp[i-c])变为dp[i] = min(dp[i],1+dp[i-c]);
完全背包问题不涉及顺序的完全背包问题,nums
和target
在内外循环都可以,但建议nums
外循环,target
内循环。下面num在外。
涉及顺序(组合问题求排列数)的target在外,如爬楼梯问题
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1,amount+1);
dp[0] = 0;
for(const int c : coins){
for(int i=1;i<=amount;i++){
if(i-c>=0){
dp[i] = min(dp[i],1+dp[i-c]);
}
}
}
return dp[amount] == amount+1?-1:dp[amount];
}
};
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
int MAX = amount + 1;
// Arrays.fill(dp, MAX);
int sz = coins.length-1;
for(int i = 1; i <= amount; ++i){
dp[i] = MAX;
for(int j = sz; j >= 0; --j){
if(i - coins[j] >= 0 && dp[i - coins[j]] != MAX){
dp[i] = Math.min(dp[i],dp[i - coins[j]]+1);
}
}
}
return dp[amount] == MAX ? -1 : dp[amount];
}
}
- 时间复杂度 O(Sn) :其中 S 是金额,n 是面额数
- 空间复杂度 O(S)