322. 零钱兑换
1.题目描述
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
示例 2:
说明:
你可以认为每种硬币的数量是无限的。
2.思路
因为为硬币可以重复使用,因此这是一个完全背包问题。完全背包只需要将 0-1 背包的逆序遍历 dp 数组改为正序遍历即可。
状态转移方程
d
p
(
n
)
=
{
0
,
n
=
0
−
1
,
n
<
0
m
i
n
(
d
p
[
n
]
,
d
p
[
n
−
c
o
i
n
]
+
1
)
,
n
>
0
,考虑当前硬币的最少数量和不考虑当前硬币的最小数量的最小值
dp(n) = \begin{cases} 0, & \text{$n=0$} \\ -1, & \text{$n<0$} \\ min(dp[n],dp[n-coin]+1), & \text{$n>0$,考虑当前硬币的最少数量和不考虑当前硬币的最小数量的最小值} \\ \end{cases}
dp(n)=⎩⎪⎨⎪⎧0,−1,min(dp[n],dp[n−coin]+1),n=0n<0n>0,考虑当前硬币的最少数量和不考虑当前硬币的最小数量的最小值
dp[i] = x 表示,当目标金额为 i 时,至少需要 x 枚硬币。
3.代码
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1,amount+1);
dp[0] = 0;
for(auto &coin : coins){
for(int j = coin;j <= amount;++j){
dp[j] = min(dp[j],dp[j-coin]+1);
}
}
return (dp[amount] == amount+1) ? -1 : dp[amount];
}
};
复杂度分析
时间复杂度:O(nk),n为金额,k为零钱种类
空间复杂度:O(n)