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: []
分析:
比1难的地方是要列出所有可能,不过有work-breaki的基础,啥都好说。
1详见:work-break-i
下面代码可行,但是内存超了,囧~,思路应该差不多,小伙伴们结合work-break-i看看吧
vector<string> wordBreak(string s, unordered_set<string> &dict) {
vector<vector<string>> stable(s.size()+1);
vector<bool> table(s.size()+1, false);
table[0]=true;
stable[0].push_back("");
bool flag;
for(int i=1;i<=s.size();++i)
{
flag = false;
for(int j=0;j<i;++j)
{
table[i] = table[j]&&(dict.find(s.substr(j,i-j))!=dict.end());
if(table[i]==true)
{
flag = true;
for(int k=0;k<stable[j].size();++k)
{
if(stable[j][k]!="")
stable[i].push_back(stable[j][k]+" "+s.substr(j,i-j));
else
stable[i].push_back(s.substr(j,i-j));
}
}
}
table[i] = flag;
}
return stable[s.size()];
}
上面代码内存超限,分析是因为表里存了太多重复的字符串了,于是我改成了表是只存哪个j能够让f(i)=f(j)&&f(j+1,i)为true,到了返回的时候用递归将结果算出来再返回。
class Solution {
public:
vector<string> GetString(vector<vector<int>> &stable, int index, string& s)
{
vector<string> res, last;
if(index == -1)
{
res.push_back("");
return res;
}
for(int i=0;i<stable[index].size();++i)
{
last = GetString(stable, stable[index][i], s);
string temp;
if(stable[index][i]!=-1)
temp = s.substr(stable[index][i], index - stable[index][i]);
else
temp ="";
cout<<temp<<endl;
for(int k=0;k<last.size();++k)
{
if(last[k]!="")
res.push_back(last[k]+" "+temp);
else
res.push_back(temp);
}
}
return res;
}
vector<string> wordBreak(string s, vector<string>& wdict) {
unordered_set<string> dict;
for(int i=0;i<wdict.size();++i)
dict.insert(wdict[i]);
vector<bool> table(s.size()+1, false);
table[0]=true;
// stable[0].push_back("");
vector<vector<int>> stable(s.size()+1);
stable[0].push_back(-1);
bool flag;
for(int i=1;i<=s.size();++i)
{
flag = false;
for(int j=0;j<i;++j)
{
table[i] = table[j]&&(dict.find(s.substr(j,i-j))!=dict.end());
if(table[i]==true)
{
flag = true;
stable[i].push_back(j);
}
}
table[i] = flag;
}
return GetString(stable, s.size(), s);
}
};
臃肿了不少,但是能过,还是ok的...接下来是看别人代码的环节,思路大同小异,唯一的差别是,这份代码最后构造字符串的时候是从前往后构造的,每次构造都要查表,如果新词在表里,就把他加入到res 里。还有就是确实代码写得不错,比我的烂代码节省不少无谓的计算,QAQ。
class Solution {
private:
unordered_set<string> words;
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
words.clear();
copy(wordDict.begin(), wordDict.end(), inserter(words, words.end()));
int n = s.size();
vector<int> dp(n + 1, 0);
dp[0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = i - 1; j >= 0; --j) {
if (dp[j]) {
if (words.count(s.substr(j, i - j))) {
dp[i] = 1;
break;
}
}
}
}
vector<string> res;
if (dp[n]) {
constructSentence(s, dp, 0, res, "");
}
return res;
}
void constructSentence(const string& s,
const vector<int>& dp,
int pos,
vector<string>& res,
string temp) {
for (int i = pos + 1; i < dp.size(); ++i) {
if (dp[i]) {
string new_word = s.substr(pos, i - pos);
if (words.count(new_word)) {
if (i + 1 == dp.size()) {
res.push_back(temp + new_word);
return;
}
constructSentence(s, dp, i, res, temp + new_word + " ");
}
}
}
}
};