题目描述
给你一个整数数组 coins
表示不同面额的硬币,另给一个整数 amount
表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0
。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
样例
输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
输入:amount = 3, coins = [2]
输出:0
解释:只用面额 2 的硬币不能凑成总金额 3。
输入:amount = 10, coins = [10]
输出:1
限制
1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins
中的所有值 互不相同。0 <= amount <= 5000
算法
(动态规划,完全背包) O(amount⋅n)
- 将总金额视为背包容量,将硬币的面额视为重量,价值视为 1,此题就是变种的固定容量完全背包问题。
- 设状态 f(j) 表示硬币总面额为 j 时的方案数。
- 初始时 f(0)=1。
- 对于每一种硬币面额 coins(i),j 从 coins(i) 枚举到 amount,累计转移 f(j)=f(j)+f(j−coins(i))。
- 最终答案为 f(amount)。
时间复杂度
- 状态数为 O(amount),转移总数为O(n),每次转移的时间复杂度为 O(1),故总时间复杂度为 O(amount⋅n)。
C++ 代码
class Solution {
public:
int change(int amount, vector<int>& coins) {
int n = coins.size();
vector<int> f(amount + 1, 0);
f[0] = 1;
for (int i = 0; i < n; i++)
for (int j = coins[i]; j <= amount; j++)
f[j] += f[j - coins[i]];
return f[amount];
}
};
for (int j = 0; j <= amount; j )
for (int i = 0; i < coins.size(); i )
为什么外循环是遍历amount就wa了呀
标准的状态转移是考虑了前 i 种硬币,总价值为 j 的方案数,通过完全背包优化成了一维。如果外层循环是 amount,会出现重复,例如总价值为 3,1+2和 2+1 就会被看做两种。
这里
f[0] = 1
表示什么含义呢?硬币总面额为 0 是只有 1 种方案,这是初始状态。
好的 谢谢。(另外多问一句,你是5:37就起床了吗!?)
我在美国hh
hh
没看懂,大佬能解释一下这个是什么思路吗?
这个是背包问题,如果没学过,可以看一下背包九讲
好的 谢谢啦 我回去看看 很晚才报的名