# Leetcode 140. Word Break II

@(LeetCode)[LeetCode | Algorithm | DP | Backtracking | DFS]

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"
]

The original problem is HERE.

## Solution #1 DP

Time: $O\left({2}^{n}\right)$$O(2^n)$
Space: $O\left({2}^{n}\right)$$O(2^n)$

$dp\left[i\right]=\left\{str\left[s:i\right)+dp\left[s\right]\phantom{\rule{thinmathspace}{0ex}}|\phantom{\rule{thinmathspace}{0ex}}str\left[s:i\right)\in \text{wordDict},\phantom{\rule{thinmathspace}{0ex}}dp\left[s\right]\ne \mathrm{\varnothing },\phantom{\rule{thinmathspace}{0ex}}s\in \left[0,i\right)\right\}$

class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
vector<vector<string> > dp(s.length() + 1, vector<string>());
dp[0].push_back(string());

unordered_set<string> dict;
for(string str : wordDict)
dict.insert(str);

if( !breakable(s, dict) )
return dp.back();

for(int i = 1; i <= s.length(); i++){
for(int j = 0; j < i; j++){
string ss = s.substr(j, i - j);
if(dp[j].size() > 0 && dict.find(ss) != dict.end()){
for(string prefix : dp[j]){
dp[i].push_back(prefix + (prefix == "" ? "" : " ") + ss);
}
}
}
}

return dp.back();
}

bool breakable(string s, unordered_set<string> &dict){
vector<bool> dp(s.length() + 1, false);
dp[0] = true;

for(int i = 1; i <= s.length(); i++){
for(int j = 0; j < i; j++){
string ss = s.substr(j, i - j);
if(dp[j] && dict.find(ss) != dict.end()){
dp[i] = true;
break;
}
}
}
return dp.back();
}
};

## Solution #2 DFS (Backtracking) with memory

Time: $O\left({2}^{n}\right)$$O(2^n)$
Space: $O\left({2}^{n}\right)$$O(2^n)$

class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> dict;
for(string str : wordDict)
dict.insert(str);

vector<string >ret = dfs(s, 0, dict);

return ret;
}

vector<string> dfs(string &s, int start, unordered_set<string> &dict){
if(memo.find(start) != memo.end())
return memo[start];

if(start == s.length()){
cout << "create memo: " << start << endl;
memo[start] = vector<string>(1, string());
return memo[start];
}

vector<string> ret;
for(int i = start; i < s.length(); i++){
string ss = s.substr(start, i - start + 1);
if(dict.find(ss) != dict.end()){
vector<string> suffixes = dfs(s, i + 1, dict);

for(string suffix : suffixes)
ret.push_back(ss + (suffix == "" ? "" : " ") + suffix);
}
}

cout << "create memo: " << start << endl;
memo[start] = ret;
return ret;
}

private:
map<int, vector<string> > memo;
};

## Conclusion

input:
"aaaaaaaaaaaaabaaaaaaaaaaaaa"
["a", "aa", "aaa", "aaaa", "aaaaa", "aaaaaa", "aaaaaaa", "aaaaaaaa", "aaaaaaaaa", "aaaaaaaaaa", "aaaaaaaaaaa", "aaaaaaaaaaaa", "aaaaaaaaaaaaa"]

Output:
[]

Backtracking通过DFS很快就能判断该句子不能被break。

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120