Day46【动态规划】139.单词拆分、多重背包

139.单词拆分

力扣题目链接/文章讲解 

视频讲解 

单词就是物品,字符串s就是背包,单词能否组成字符串s,就是问物品能不能把背包装满。

拆分时可以重复使用字典中的单词,说明就是一个完全背包!

但是,正如我们之前说过,如果非要套完全背包的解题思路,有时候会很复杂,反而禁锢了自己。本题就按照单纯的动态规划问题的解法,直接动态规划五部曲反倒十分好理解

1、定义 dp 数组下标及值含义

dp[i]:下标 i 表示字符串 s 的前 i 个字符组成的字符串,dp[i] 的值表示这前 i 个字符组成的字符串是否能被空格拆分成若干个字典中出现的单词,ture 表示能,false 表示不能

2、确定递推公式

怎么推出 dp[i],即怎么知道字符串前 i 个字符组成的字符串能否被空格拆分出字典中的单词?

如果确定 dp[j] 是 true,且字符串下标为 [j, i - 1] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )

怎么理解:串前 i 个字符组成的字符串能被按要求拆分,一定是串前 j 个字符组成的字符串能被按要求拆分,以及串第 j + 1 个字符到第 i 个字符(即下标为 j 到 i - 1)构成的子串出现在字典里

所以递推公式是 if(字符串下标 [j, i - 1] 这个区间的子串出现在字典里 && dp[j] == true) 那么 dp[i] = true。

3、dp 数组初始化

从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了

那么 dp[0] 有没有意义呢?

dp[0] 表示如果字符串为空的话,说明出现在字典里。

但题目中说了“给定一个非空字符串 s” 所以测试数据中不会出现 i 为 0 的情况,那么 dp[0] 初始为 true 完全就是为了推导公式

下标非 0 的 dp[i] 初始化为false,只要没有被覆盖说明都是不可拆分为一个或多个在字典中出现的单词

4、确定遍历顺序

从左向右遍历填充

5、打印 dp 数组验证

代码如下

class Solution {
public:
    bool wordBreak(string s, vector& wordDict) {
        auto wordDictSet = unordered_set  ();
        for (auto word: wordDict) {
            wordDictSet.insert(word);
        }    // 利用哈希组织,能够加快find效率
        
        // dp[i]表示前i个字符构成字符串能够按题意拆分
        auto dp = vector  (s.size() + 1);

        // 初始化
        dp[0] = true;

        for (int i = 1; i <= s.size(); ++i) {    // 从左向右遍历填充
            for (int j = 0; j < i; ++j) {
                if (dp[j] && wordDictSet.find(s.substr(j, i - j)) != wordDictSet.end()) {   // 前j个字符能拆分,且第j+1个字符到第i个字符构成的子串出现在字典
                    dp[i] = true;
                }
            }
        }

        return dp[s.size()];
    }
};

多重背包 

文章讲解 

力扣上没有相关题目,简单介绍一下核心思路就行:转化为 0-1 背包

例: 

背包最大重量为10

物品为

重量 价值 数量
物品0 1 15 2
物品1 3 20 3
物品2 4 30 2

问背包能背的物品最大价值是多少?

上述问题为多重背包问题,可以将问题转化为转化为:

背包最大重量为10

物品为

重量 价值 数量
物品0 1 15 1
物品0 1 15 1
物品1 3 20 1
物品1 3 20 1
物品1 3 20 1
物品2 4 30 1
物品2 4 30 1

毫无区别,这就转成了一个 0-1 背包问题了,每个物品只用一次


回顾总结 

文章讲解 

背包问题终于结束了! 

在解背包问题的时候,我们都是按照如下五部来逐步分析

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组 

背包问题这个部分,我们主要需要掌握:

  • 二维版本的 dp 数组解决背包问题应该怎么解决(重点掌握,因为有方法论)
  • 如何利用滚动数组进行状态压缩为一维 dp(重点掌握,因为有方法论)
  • 对于背包问题,如果太复杂, 怎么跳出禁锢思维,将背包问题当成单纯的动态规划问题,直接动态规划五部曲推一维 dp(这种比较靠缘分,主要看能不能想出递推公式)

你可能感兴趣的:(代码随想录,动态规划,算法,c++,leetcode,数据结构)