完全背包
完全背包和01背包不一样的地方在于,对于同一样物品,可以选择无限次。
一维压缩dp数组
在代码上,差异体现在,在遍历背包的时候01背包需要倒序遍历,保证物品只被使用过一次。
完全背包在遍历背包的时候是正序遍历,物品可以使用多次。
代码
def test_CompletePack():
weight = [1, 3, 4]
value = [15, 20, 30]
bagWeight = 4
dp = [0] * (bagWeight + 1)
for i in range(len(weight)): # 遍历物品
for j in range(weight[i], bagWeight + 1): # 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(dp[bagWeight])
test_CompletePack()
518. 零钱兑换 II
思路
01背包的此类型题是494. 目标和。本题是在完全背包下求装满背包的组合的个数。
组合与排序
在求装满背包有几种方案的时候,认清遍历顺序是非常关键的。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
代码
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0]*(amount + 1)
dp[0] = 1
# 遍历物品
for i in range(len(coins)):
# 遍历背包
for j in range(coins[i], amount + 1):
dp[j] += dp[j - coins[i]]
return dp[amount]
- 时间复杂度:
O(mn),
其中m
是amount
,n
是coins
的长度 - 空间复杂度:
O(m)
377. 组合总和 Ⅳ
思路
完全背包的排列版本。
代码
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
dp = [0] * (target + 1)
dp[0] = 1
for j in range(0, target + 1):
for num in nums:
if j - num >= 0:
dp[j] += dp[j - num]
return dp[-1]
- 时间复杂度:
O(target * n)
,其中n
为nums
的长度 - 空间复杂度:
O(target)