算法Day46 | 139.单词拆分,多重背包, 背包问题总结

Day46

    • 139.单词拆分
    • 多重背包
    • 背包问题总结

139.单词拆分

题目链接:139.单词拆分
dp数组含义:字符串长度为 i 能被单词组成,则dp[i] = true
递推公式:有j < i,如果dp[j] == true && i - j 出现在单词中,dp[i]为true
初始化dp[0] = true,其他为false

为了便于对比与字符串和字典中的单词是否重复,因此将vector容器改成unordered_set

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) {
                if (dp[j] && wordSet.find(s.substr(j, i - j)) != wordSet.end()/*判断是否出现在集合中*/)
                    dp[i] = true;
            }
        }
        return dp.back();
    }
};

多重背包

就是有个数的01背包问题。完全背包中物体使用次数是无限制的,多重背包中的物体使用的次数是有限制的,就可以转化为01背包问题。如有物品{a, b, c},其中b有两个,此问题为多重背包问题,因此可以将多重背包问题转化为{a, b, b, c}01背包问题。

void test_multipack() {
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    vector<int> nums = {2, 3, 2};
    int bagWeight = 10;
    for (int i = 0; i < nums.size(); i++) {
        while (--nums[i]) { // nums[i]保留到1,把其他物品都展开
            weight.push_back(weight[i]);
            value.push_back(value[i]);
        }
    }

    vector<int> dp(bagWeight + 1, 0);
    for(int i = 0; i < weight.size(); i++) { // 遍历物品
        for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
        for (int j = 0; j <= bagWeight; j++) {
            cout << dp[j] << " ";
        }
        cout << endl;
    }
    cout << dp[bagWeight] << endl;
}

背包问题总结

最终要的就是根据题意来确认dp数组,通常直接将dp数组表示为最后所求的答案。
通过题意来具体修改递推公式初始化
01背包有固定的遍历顺序,完全背包根据背包中的物品顺序是否有序,而选择物品和背包的遍历顺序。
有的题目需要自定义物品或者背包,注意一些细节。


你可能感兴趣的:(刷题日志,算法,leetcode,动态规划,数据结构,c++)