给定硬币面额和种类,给定总金额,求用最少个数的硬币去组成这个金额
https://leetcode-cn.com/problems/coin-change
和leetcode 518 类似
Example 1:
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
1. 这里是问最小的硬币数量,且存在组合不了的情况,所以直接用MAX初始化数组
2. 这里就要初始化dp[0]=0,这里就能够让面额2硬币,对于金额2来说有d[2] = min d[2-2]+1,d[2] = d[0]+1=1
3. 转移方程就是dp[j] = min(dp[j-coins[i]]+1, dp[j]); 这一行左边+1和上一行的最小值
4. 注意是可以一个硬币多用,所以内层循环顺着来(完全背包)
如图,对于上面的example1 来说
从左至右更新
背包 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
初始化 | 0 | - | - | - | - | - | - | - | - | - | - | - |
1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
2 | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 5 | 5 | 6 |
5 | 0 | 1 | 1 | 2 | 2 | 1 | 2 | 2 | 3 | 3 | 2 | 3 |
所以输出dp[11] = 3
class Solution {
public:
int coinChange(vector<int>& coins,int amount) {
const int MAX = 0x7fffffff-1;
int dp[amount+1];
fill(dp,dp+amount+1,MAX);
dp[0] = 0;
int n = coins.size();
for(int i=0;i<n;i++){
for(int j=coins[i];j<=amount;j++){
if(dp[j] !=MAX ||dp[j-coins[i]]!=MAX)
//上面的dp[j] !=MAX 可以去掉
dp[j] = min(dp[j-coins[i]]+1, dp[j]);
}
}
return dp[amount] == MAX? -1:dp[amount];
}
};