题目描述:
给你一个整数数组 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
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析:
这道题和279. 完全平方数 十分相似,都是使用动态规划。
我们设定数组dp[i]代表总金额为i时,所组成的最小硬币数。
假设给了三种硬币[1,2,5],面对总金额为i,我们要思考如何组成总金额i呢?一种好的办法就是,我们先组成i-1,i-2,i-5这三种金额,然后让总金额为i-1的再加上一个硬币1,总金额为i-2的再加上一个硬币2,总金额为i-5的再加上一个硬币5。总金额为i-1的方案对应的最小硬币数为dp[i-1],总金额为i-2的方案对应的最小硬币数为dp[i-2],总金额为i-5的方案对应的最小硬币数为dp[i-5]。因此,dp[i]=dp[i-1]+1 or dp[i]=dp[i-2]+1 or dp[i]=dp[i-5]+1,我们选取三者中的最小值,来赋给dp[i]即可。
详细分析请看题解:
代码如下:
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
// dp[i]代表凑成总金额为i所需的 最少的硬币个数
int dp[10005];
dp[0]=0;
// 依次计算dp[i]
for(int i=1;i<=amount;i++)
{
// 设置计算dp[i]时的最小值
int min=2147483647;
// 依次选取coins[j],在i-coins[j]的基础上,加上coins[j]
// 由于总金额为i-coins[j],最少硬币数为dp[i-coins[j]],之前已经计算过
// 总金额i就是在总金额为i-coins[j]的基础上,再加上coins[j]
// 因此,总金额i的最少硬币数dp[i],等于总金额为i-coins[j]的硬币数dp[i-coins[j]]+总金额为conins[j]的硬币数1
// 即dp[i]=min(dp[i-coins[j]])+1
for(int j=0;j<coins.size();j++)
{
if(coins[j]<=i&&min>dp[i-coins[j]]&&dp[i-coins[j]]!=-1)
min=dp[i-coins[j]];
}
// 如果没有找到组成金额i的最少硬币数,说明当前所给硬币无法组成金额i,对应dp[i]赋值为-1
if(min==2147483647)
dp[i]=-1;
else
dp[i]=1+min;
}
// 返回计算后的结果
return dp[amount];
}
};