代码随想录算法训练营第50天|动态规划part08|139.单词拆分、关于多重背包,你该了解这些!、背包问题总结篇!
139. 单词拆分
139. 单词拆分
思路:
单词就是物品,字符串s就是背包
拆分时可以重复使用字典中的单词,说明就是一个完全背包!
动规五部曲分析如下:
- 确定dp数组以及下标的含义
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数组如何初始化
从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。
- 确定遍历顺序
完全背包
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
我在这里做一个总结:
求组合数:动态规划:518.零钱兑换II (opens new window)求排列数:动态规划:377. 组合总和 Ⅳ (opens new window)、动态规划:70. 爬楼梯进阶版(完全背包) (opens new window)求最小数:动态规划:322. 零钱兑换 (opens new window)、动态规划:279.完全平方数
本题其实我们求的是排列数
- 举例推导dp[i]
dp[s.size()]就是最终结果。
代码:
python
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
dp = [False] * (len(s)+1)
dp[0] = True
for j in range(1, len(s)+1):
for word in wordDict:
if j >= len(wordDict):
dp[j] = dp[j] or (dp[j-len(word)] and s[j-len(word):j] == word)
return dp[len(s)]
关于多重背包,你该了解这些!
有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。
多重背包和01背包是非常像的, 为什么和01背包像呢?
每件物品最多有Mi件可用,把Mi件摊开,其实就是一个01背包问题了。
例如:
背包最大重量为10。
物品为:
重量 | 价值 | 数量 | |
---|---|---|---|
物品0 | 1 | 15 | 2 |
物品1 | 3 | 20 | 3 |
物品2 | 4 | 30 | 2 |
问背包的最大价值是多少?
将物品的数量进行拆分转化成0-1背包问题
重量 | 价值 | 数量 | |
---|---|---|---|
物品0 | 1 | 15 | 1 |
物品0 | 1 | 15 | 1 |
物品2 | 3 | 20 | 1 |
物品2 | 3 | 20 | 1 |
物品2 | 3 | 20 | 1 |
物品3 | 4 | 30 | 1 |
物品3 | 4 | 30 | 1 |
代码:
python
def multi_pack(weight, value, nums, bagweight):
# 拆分
for i in range(len(nums)):
while nums[i] > 1:
weight.append(weight[i])
value.append(value[i])
nums[i] -= 1
dp = [0] * (bagweight+1)
# dp[j] = max(dp[j], dp[j-weight[i]] + value[i])
for i in range(len(weight)+1):
for j in reversed(range(weight[i], bagweight+1)):
dp[j] = max(dp[j], dp[j-weight[i]] + value[i])
return dp[bagweight]
背包问题总结篇!
背包问题总结篇!