139. 单词拆分
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
# 单词就是物品,字符串s就是背包,单词能否组成字符串s,就是问物品能不能把背包装满。
# 本题求的是排列数 因为要考虑顺序
# 求排列数就是外层for遍历背包,内层for循环遍历物品
dp = [False]*(len(s) + 1)
dp[0] = True
# 遍历背包
for j in range(1, len(s) + 1):
# 遍历单词
for word in wordDict:
if j >= len(word):
dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
return dp[len(s)]
多重背包
有N种物品和一个容量为V的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi.
不同点是每个物品有自己的数量Mi
每件物品最多有Mi件可用,把Mi件摊开,其实就是01背包问题。
时间复杂度:O(m × n × k),m:物品种类个数,n背包容量,k单类物品数量
或者再加入一层循环表示物品数量的迭代
随想录代码
def test_multi_pack1():
'''版本一:改变物品数量为01背包格式'''
weight = [1, 3, 4]
value = [15, 20, 30]
nums = [2, 3, 2]
bag_weight = 10
for i in range(len(nums)):
# 将物品展开数量为1
while nums[i] > 1:
weight.append(weight[i])
value.append(value[i])
nums[i] -= 1
dp = [0]*(bag_weight + 1)
# 遍历物品
for i in range(len(weight)):
# 遍历背包
for j in range(bag_weight, weight[i] - 1, -1):
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(" ".join(map(str, dp)))
def test_multi_pack2():
'''版本:改变遍历个数'''
weight = [1, 3, 4]
value = [15, 20, 30]
nums = [2, 3, 2]
bag_weight = 10
dp = [0]*(bag_weight + 1)
for i in range(len(weight)):
for j in range(bag_weight, weight[i] - 1, -1):
# 以上是01背包,加上遍历个数
for k in range(1, nums[i] + 1):
if j - k*weight[i] >= 0:
dp[j] = max(dp[j], dp[j - k*weight[i]] + k*value[i])
print(" ".join(map(str, dp)))
背包总结
dp数组存放的值就是结果
01背包vs完全背包
求组合数就是外层for循环遍历物品,内层for遍历背包。
求排列数就是外层for遍历背包,内层for循环遍历物品。