今日任务
- 139.单词拆分
- 关于多重背包,你该了解这些!
- 背包问题总结篇!
139.单词拆分 - Medium
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
思路:单词就是物品,字符串s就是背包,单词能否组成字符串s,就是问物品能不能把背包装满。拆分时可以重复使用字典中的单词,那这就是一个完全背包问题
- 时间复杂度:O(n^3),因为substr返回子串的副本是O(n)的复杂度(这里的n是substring的长度)
- 空间复杂度:O(n)
class Solution {
public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> wordSet(wordDict.begin(), wordDict.end());vector<bool> dp(s.size() + 1, false);dp[0] = true;for (int i = 1; i <= s.size(); i++) { // 遍历背包for (int j = 0; j < i; j++) { // 遍历物品string word = s.substr(j, i - j); //substr(起始位置,截取的个数)if (wordSet.find(word) != wordSet.end() && dp[j]) {dp[i] = true;}}}return dp[s.size()];}
};
多重背包理论基础
理论基础:代码随想录
有N种物品和一个容量为V 的背包。
第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。
求解将哪些物品装入背包可使这些物品的耗费的空间总和不超过背包容量且价值总和最大。
多重背包和01背包是非常像的, 每件物品最多有Mi件可用,把Mi件摊开,其实就是一个01背包问题了。使用这种方式实现的时间复杂度:O(m × n × k),m:物品种类个数,n背包容量,k单类物品数量
#include<iostream> #include<vector> using namespace std; int main() {int bagWeight,n;cin >> bagWeight >> n;vector<int> weight(n, 0);vector<int> value(n, 0);vector<int> nums(n, 0);for (int i = 0; i < n; i++) cin >> weight[i];for (int i = 0; i < n; i++) cin >> value[i];for (int i = 0; i < n; i++) cin >> nums[i];vector<int> dp(bagWeight + 1, 0);for(int i = 0; i < n; i++) { // 遍历物品for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量// 以上为01背包,然后加一个遍历个数for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) { // 遍历个数dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);}}}cout << dp[bagWeight] << endl; }
背包问题总结
总结:代码随想录
背包问题关系图:
递推公式
- 问能否能装满背包(或者最多装多少):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循环的先后顺序无所谓