今日任务
目录
139.单词拆分 - Medium
多重背包理论基础
背包问题总结
递推公式
遍历顺序
139.单词拆分 - Medium
题目链接:力扣-139. 单词拆分
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
提示:单词就是物品,字符串s就是背包,单词能否组成字符串s,就是问物品能不能把背包装满。拆分时可以重复使用字典中的单词,那这就是一个完全背包问题
class Solution:def wordBreak(self, s: str, wordDict: List[str]) -> bool:dp = [False] * (len(s) + 1)dp[0] = Truefor i in range(1, len(s)+1):for j in range(i):if dp[j] and s[j:i] in wordDict:dp[i] = Truebreakreturn dp[len(s)]
多重背包理论基础
理论基础:代码随想录
有N种物品和一个容量为V 的背包。
第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。
求解将哪些物品装入背包可使这些物品的耗费的空间总和不超过背包容量且价值总和最大。
多重背包和01背包是非常像的, 每件物品最多有Mi件可用,把Mi件摊开,其实就是一个01背包问题了。使用这种方式实现的时间复杂度:O(m × n × k),m:物品种类个数,n背包容量,k单类物品数量
def test_multi_pack():weight = [1, 3, 4]value = [15, 20, 30]nums = [2, 3, 2]bagWeight = 10# 将数量大于1的物品展开for i in range(len(nums)):while nums[i] > 1:weight.append(weight[i])value.append(value[i])nums[i] -= 1dp = [0] * (bagWeight + 1)for i in range(len(weight)): # 遍历物品for j in range(bagWeight, weight[i] - 1, -1): # 遍历背包容量dp[j] = max(dp[j], dp[j - weight[i]] + value[i])for j in range(bagWeight + 1):print(dp[j], end=" ")print()print(dp[bagWeight])test_multi_pack()
另一种实现方式,就是把每种商品遍历的个数放在01背包里面在遍历一遍,时间复杂度同上
def test_multi_pack():weight = [1, 3, 4]value = [15, 20, 30]nums = [2, 3, 2]bagWeight = 10dp = [0] * (bagWeight + 1)for i in range(len(weight)): # 遍历物品for j in range(bagWeight, 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])# 打印一下dp数组for j in range(bagWeight + 1):print(dp[j], end=" ")print()print(dp[bagWeight])test_multi_pack()
背包问题总结
总结:代码随想录
背包问题关系图:
递推公式
- 问能否能装满背包(或者最多装多少):dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
- 问装满背包有几种方法:dp[j] += dp[j - nums[i]]
- 问背包装满最大价值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
- 问装满背包所有物品的最小个数:dp[j] = min(dp[j - coins[i]] + 1, dp[j])
遍历顺序
01背包
- 二维dp数组01背包:先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历
- 一维dp数组01背包:只能先遍历物品再遍历背包容量,且第二层for循环是从大到小遍历
完全背包
- 纯完全背包:一维dp数组实现,先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历
求组合数:外层for循环遍历物品,内层for遍历背包
求排列数:外层for遍历背包,内层for循环遍历物品
求最小数:两层for循环的先后顺序无所谓