1、题目描述:
2、题解:
转化为完全背包:coins数组的元素为物品的重量,amount为背包的容量。而物品的数量无限。
状态定义:
dp[i][j] 若只使用前 i 个物品,当背包容量为 j 时,有 dp[i][j] 种方法可以装满背包。
对于本题,若只使用 coins 中的前 i 个硬币的面值,若想凑出金额 j,有 dp[i][j] 种凑法。
大致的伪代码:
int dp[N+1][amount+1]
dp[0][..] = 0
dp[..][0] = 1
for i in [1..N]:
for j in [1..amount]:
把物品 i 装进背包,
不把物品 i 装进背包
return dp[N][amount]
状态转移:
dp[i][j] = dp[i - 1][j] + dp[i][j-coins[i-1]]
解释:
如果你不把这第 i 个物品装入背包,也就是说你不使用 coins[i] 这个面值的硬币,那么凑出面额 j 的方法数 dp[i][j] 应该等于 dp[i-1][j],继承之前的结果。
如果你把这第 i 个物品装入了背包,也就是说你使用 coins[i] 这个面值的硬币,那么 dp[i][j] 应该等于 dp[i][j-coins[i-1]]。
初始化:
dp[i][0] = 1,当总金额为0时,只有一种方案0.
伪代码如下:
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= amount; j++) {
if (j - coins[i-1] >= 0)
dp[i][j] = dp[i - 1][j] + dp[i][j-coins[i-1]];
return dp[N][W]
写成python语音:
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
#动态规划,完全背包
n = len(coins)
dp = [[0] * (amount + 1) for _ in range(n + 1)]
for i in range(n + 1):
dp[i][0] = 1
for i in range(1,n + 1):
for j in range(1,amount + 1):
if j >= coins[i - 1]:
dp[i][j] = dp[i - 1][j] + dp[i ][j - coins[i - 1]]
else:
dp[i][j] = dp[i - 1][j]
return dp[-1][-1]
状态压缩:
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
#动态规划,完全背包,空间优化
n = len(coins)
dp = [0] * (amount + 1)
dp[0] = 1
for i in range(n + 1):
for j in range(1,amount + 1):
if j >= coins[i ]:
dp[j] = dp[j] + dp[j - coins[i]]
return dp[-1]