「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
1、题目
给你一个整数数组 coins
表示不同面额的硬币,另给一个整数 amount
表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0
。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32
位带符号整数。
示例 1:
1 | ini复制代码输入:amount = 5, coins = [1, 2, 5] |
示例 2:
1 | ini复制代码输入:amount = 3, coins = [2] |
示例 3:
1 | ini复制代码输入:amount = 10, coins = [10] |
提示:
1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins
中的所有值 互不相同0 <= amount <= 5000
2、思路
(动态规划,完全背包)
二维分析
状态表示: f[i][j]
表示从前i
种硬币中选,且总金额恰好为j
的所有选法集合的方案数。
那么f[n][amount]
就表示表示从前n
种硬币中选,且总金额恰好为amount
的所有选法集合的方案数,即为答案。
集合划分:
按照第i
种硬币可以选 0
个,1
个,2
个,3
个,,,,k
个划分集合 f[i][j]
。其中k*coin[i] <= j
,也就是说在背包能装下的情况下,枚举第i
种硬币可以选择几个。
- 第
i
种硬币选0
个,f[i][j] = f[i-1][j]
- 第
i
种硬币选1
个,f[i][j] = f[i-1][j - coins[i]]
- 第
i
种硬币选k
个,f[i][j] = f[i-1][j - k*coins[i]]
状态计算:
f[i][j] = f[i-1][j]+f[i-1][j-coins[i]]+f[i-1][j-2*coins[i]],,,,,,+f[i-1][j-k*coins[i]]
。
初始化条件:
f[0][0] = 1
,使用0
种硬币币,凑0
元钱,也是一种方案。
时间复杂度分析: O(amount2∗n)O(amount^2*n)O(amount2∗n),其中 amountamountamount是总金额,nnn是数组 coinscoinscoins的长度。
3、二维c++代码
1 | c复制代码class Solution { |
4、二维java代码
1 | java复制代码class Solution { |
5、一维优化
二维完全背包求解方案时间复杂度较高,考虑一维优化。
v
代表第i
种硬币的面值
f[i][j] = f[i-1][j] + f[i-1][j-v]+f[i-1][j-2v]+,,,,,+f[i-1][j-kv])
f[i][j-v] = f[i-1,[j-v]+f[i-1][j-2v]+,,,,,+f[i-1][j-kv])
因此:
f[i][j] = f[i-1][j]+f[i][j-v])
图示:
去掉物品种类维度,状态计算方程为: f[j] = f[j] + f[j-v]
时间复杂度分析: O(amount∗n)O(amount*n)O(amount∗n) ,其中 amountamountamount是总金额,nnn是数组 coinscoinscoins的长度。
6、一维c++代码
1 | c复制代码class Solution { |
7、一维java代码
1 | java复制代码class Solution { |
原题链接: 518. 零钱兑换 II
本文转载自: 掘金