Leetcode 518.零钱对换 II
1 题目描述(Leetcode题目链接)
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
输入: 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。
注意:
你可以假设:
- 0 <= amount (总金额) <= 5000
- 1 <= coin (硬币面额) <= 5000
- 硬币种类不超过 500 种
- 结果符合 32 位符号整数
2 题解
本题为背包问题,可以定义二维数组
D
P
[
i
]
[
j
]
DP[i][j]
DP[i][j]为前
i
i
i枚硬币组成
j
j
j金额的组合,初始化第一行全零,并且
D
P
[
0
]
[
0
]
=
1
DP[0][0] = 1
DP[0][0]=1(意思为前0种硬币组成0块钱的组合数就是1种),从第二行开始遍历,状态转移方程为:
D
P
[
i
]
[
j
]
=
{
D
P
[
i
−
1
]
[
j
]
+
D
P
[
i
]
[
j
−
c
o
i
n
s
[
i
−
1
]
]
i
f
j
−
c
o
i
n
s
[
i
−
1
]
≥
0
D
P
[
i
−
1
]
[
j
]
o
t
h
e
r
w
i
s
e
DP[i][j] = \begin{cases} DP[i-1][j] + DP[i][j - coins[i-1]]&if \ \ \ j-coins[i - 1] \ge 0\\ DP[i - 1][j]&otherwise \end{cases}
DP[i][j]={DP[i−1][j]+DP[i][j−coins[i−1]]DP[i−1][j]if j−coins[i−1]≥0otherwise
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
size = len(coins)
dp = [([0]*(amount + 1)) for i in range(size + 1)]
dp[0][0] = 1
for i in range(1, size + 1):
for j in range(amount + 1):
if j - coins[i-1] >= 0:
dp[i][j] = dp[i][j - coins[i-1]] + dp[i - 1][j]
else:
dp[i][j] = dp[i - 1][j]
return dp[size][amount]
由于每次遍历一行,一行中元素的改变只与上一行有关,因此可以使用一维数组完成。
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
size = len(coins)
dp = [0]*(amount + 1)
dp[0] = 1
for coin in coins:
for i in range(amount + 1):
if i - coin >= 0:
dp[i] += dp[i - coin]
return dp[amount]