LeetCode: 140. Word Break II

题目描述

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences.

Note:
The same word in the dictionary may be reused multiple times in the segmentation.
You may assume the dictionary does not contain duplicate words.
Example 1:

Input:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
Output:
[
  "cats and dog",
  "cat sand dog"
]

Example 2:

Input:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
Output:
[
  "pine apple pen apple",
  "pineapple pen apple",
  "pine applepen apple"
]
Explanation: Note that you are allowed to reuse a dictionary word.

Example 3:

Input:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
Output:
[]

解题思路

解题思路同 LeetCode: 139. Word Break 题解
此题不同之处在于,需要将计算过程记录下来,后面根据记录的计算过程构造最优解。

AC 代码

class Solution 
{
private:
    // Compute the value of an optimal solution, in a bottom-up fashion.
    // 返回值表示是否能成功分割
    void ComputeOptSolutionValue(string s, const vector<string>& wordDict, 
                                 vector<vector<bool>>& frontWordBreak)
    {
        // 初始化:定义空串能被空串拼凑出
        frontWordBreak[0][0] = true;

        // 自底向上计算最优解的值
        for(size_t i = 1; i <= s.size(); ++i)
        {
            for(size_t j = 1; j <= wordDict.size(); ++j)
            {
                if(wordDict[j-1].size() > i) continue;

                if(s.substr(i-wordDict[j-1].size(), wordDict[j-1].size()) == wordDict[j-1])
                {
                    for(size_t k = 0; k <= wordDict.size(); ++k)
                    {
                        frontWordBreak[i][j] =
                            (frontWordBreak[i][j] || frontWordBreak[i-wordDict[j-1].size()][k]);
                    }
                }
            }
        }
    }

    // Construct an optimal solution from computed infomation.
    void ConstructOptSolution(const vector<string>& wordDict,
                              const vector<vector<bool>>& frontWordBreak, 
                              int curPos, vector<string>& recordSolution, 
                              vector<vector<string>> & solutions)
    {
        if(curPos == 0)
        {
            solutions.push_back(recordSolution);
        }

        for(size_t i = 1; i <= wordDict.size(); ++i)
        {
            if(curPos >= wordDict[i-1].size() && frontWordBreak[curPos][i] == true)
            {
                recordSolution.push_back(wordDict[i-1]);
                curPos-wordDict[i-1].size(), recordSolution, solutions);
                recordSolution.pop_back();
            }
        }
    }
public:
    vector<string> wordBreak(string s, vector<string>& wordDict) 
    {
        // frontWordBreak[i][j]: s 的前 i 个 字符是否是由 wordDict 构成(要求其后缀是 wordDict[j-1])
        vector<vector<bool>> frontWordBreak(s.size()+1);
        for(size_t i = 0; i < frontWordBreak.size(); ++i)
        {
            frontWordBreak[i].resize(wordDict.size()+1, false);
        }

        ComputeOptSolutionValue(s, wordDict, frontWordBreak);

        // 构造最优解
        vector<string> recordSolution;
        vector<vector<string>> solutions;
        ConstructOptSolution(wordDict, frontWordBreak, s.size(), recordSolution, solutions);

        vector<string> ans;
        for(size_t i = 0; i < solutions.size(); ++i)
        {
            string str;
            for(size_t j = 0; j < solutions[i].size(); ++j)
            {
                if(j == 0) str += solutions[i][j];
                else str =  solutions[i][j] + " " + str;
            }

            ans.push_back(str);
        }
        return ans;
    }
};