力扣 139. 单词拆分

题目来源:https://leetcode.cn/problems/word-break/description/

力扣 139. 单词拆分_第1张图片

C++题解:将该题视为完全背包问题,因为每个单词都可以多次用。动规五部曲分析如下:

  1. 确定dp数组以及下标的含义。dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词
  2. 确定递推公式。对于一个单词长度为mm,如果dp[i-mm]是true的话,判断该单词是否可以使用,可以的话dp[i]为true。如果dp[i]已经为true的话,则跳出循环。
  3. dp数组如何初始化。dp[0]=true。下标非0的dp[i]初始化为false,只要没有被覆盖说明都是不可拆分为一个或多个在字典中出现的单词。
  4. 确定遍历顺序。本题其实我们求的是排列数,所以说,本题一定是先遍历背包,再遍历物品,这样每次背包扩容的时候,物品才可以再次使用。
  5. 举例推导dp[i]。
class Solution {
public:
    bool wordBreak(string s, vector& wordDict) {
        int len = wordDict.size();
        int chang = s.size();
        vector dp(chang+1, false);
        dp[0] = true;
        for(int i = 1; i <= chang; i++) {
            for(int j = 0; j < len; j++) {
                if(dp[i]) break;
                int mm = wordDict[j].size();
                if(i >= mm && dp[i-mm]) {
                    bool tmp = true;
                    for(int k = 0; k < mm; k++) {
                        if(wordDict[j][k] != s[i - mm + k]) {tmp = false; break;}
                    }
                    dp[i] = tmp;
                }
            }
        }
        return dp[chang];
    }
};

代码随想录题解:使用unordered_set去重,并且查找截取的字符串。

class Solution {
public:
    bool wordBreak(string s, vector& wordDict) {
        unordered_set wordSet(wordDict.begin(), wordDict.end());
        vector 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()];
    }
};

C++题解2(来源代码随想录):回溯算法。将s进行枚举分割,判断是否在字典里出现过。

class Solution {
private:
    bool backtracking (const string& s,
            const unordered_set& wordSet,
            vector& memory,
            int startIndex) {
        if (startIndex >= s.size()) {
            return true;
        }
        // 如果memory[startIndex]不是初始值了,直接使用memory[startIndex]的结果
        if (!memory[startIndex]) return memory[startIndex];
        for (int i = startIndex; i < s.size(); i++) {
            string word = s.substr(startIndex, i - startIndex + 1);
            if (wordSet.find(word) != wordSet.end() && backtracking(s, wordSet, memory, i + 1)) {
                return true;
            }
        }
        memory[startIndex] = false; // 记录以startIndex开始的子串是不可以被拆分的
        return false;
    }
public:
    bool wordBreak(string s, vector& wordDict) {
        unordered_set wordSet(wordDict.begin(), wordDict.end());
        vector memory(s.size(), 1); // -1 表示初始化状态
        return backtracking(s, wordSet, memory, 0);
    }
};

你可能感兴趣的:(开始C++吧,leetcode,算法,c++,动态规划,背包问题,回溯算法)