目录
- 139.单词拆分
- 思路
- 代码
- 多重背包
- 背包问题总结
139.单词拆分
Leetcode
思路
dp[i]
: 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词。- 如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )
所以递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true。 - 初始化:从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。
下标非0的dp[i]初始化为false,只要没有被覆盖说明都是不可拆分为一个或多个在字典中出现的单词。 - 遍历顺序:字符串的顺序是需要注意的,所以此题实际上是排列题。比如说“leetcode”不能反过来说是“codeleet”。所以我们在求的时候先遍历背包容量再遍历物品。
代码
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
dp = [False] * (len(s) + 1)
dp[0] = True
for i in range(1, len(s) + 1):
for word in wordDict:
if i >= len(word):
if dp[i]:
break
if s[i-len(word) : i] == word and dp[i-len(word)]:
dp[i] = True
return dp[len(s)]
- 时间复杂度:
O(n^3)
,因为substr返回子串的副本是O(n)
的复杂度(这里的n是substring的长度) - 空间复杂度:
O(n)
多重背包
多重背包可以看做是01背包的超级加倍版本。
有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。
每个物品可用的数量有固定的使用次数,不是只有一次,也不是有无限次。
解题关键
每件物品最多有Mi件可用,把Mi件摊开,其实就是一个01背包问题了。
经过如下转换:
将Mi件物品摊开的代码:
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] -= 1
背包问题总结
总结参考卡哥的文章
链接
海螺人总结的图: