题目
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
说明:
你可以认为每种硬币的数量是无限的。
思路:动态规划
硬币无限,完全背包问题。动态规划。
- 状态方程定义dp[i]表示凑成总金额i所需的最少硬币个数。
- 初试dp[0]=0,最终要求的是dp[amount]
- 状态转移方程:对于每一种硬币coins[j],我可以选择放进来或者不放:
- 如果不放,那么dp[i]保持不变;
- 如果放进来,那么就还需要凑减去当前硬币额的数,即dp[i]=dp[i-coins[j]]+1。
- 最终结果要取两者的最小值,即dp[i] = min(dp[i], dp[i-coins[j]]+1);
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
/*
硬币无限,完全背包问题。动态规划。
状态方程定义dp[i]表示凑成总金额i所需的最少硬币个数。
初试dp[0]=0,最终要求的是dp[amount]
状态转移方程:对于每一种硬币coins[j],我可以选择放进来或者不放。如果不放,那么dp[i]保持不变;如果放进来,那么就还需要凑减去当前硬币额的数,即dp[i]=dp[i-coins[j]]+1。最终结果要取两者的最小值,即dp[i] = min(dp[i], dp[i-coins[j]]+1);
*/
if( coins.size()==0 || amount<0 )
return -1;
if( amount == 0 )
return 0;
vector<int> dp(amount+1, amount+1);
dp[0] = 0; //初始化
for(int i=0; i<=amount; i++){ //总额从少到多
for(int j=0; j<coins.size(); j++){//每个面额都要试一次
if( i >= coins[j] ){
//当前硬币放 or 不放
dp[i] = min(dp[i], dp[i-coins[j]]+1); //注意判断i-coins[j]
}
}
}
if( dp[amount]==(amount+1) )
return -1;
else
return dp[amount];
}
};