Word Break II
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.
Return all such possible sentences.
For example, given
s = "catsanddog"
,
dict = ["cat", "cats", "and", "sand", "dog"]
.
A solution is ["cats and dog",
"cat sand dog"]
.
思路:先用动态规划中word break I 时的解法求出所有有效单词的开始下标,然后根据有效的单词开始下标,进行深度遍历,
收集所有有效的单词
class Solution {
public:
void collectStr(string &s, string tmpstr, vector<int> &vi, int cur, vector<string> &vs, unordered_set<string> &dict){
if(cur + 1 >= vi.size()){
if(tmpstr.back() == ' ') tmpstr.pop_back(); //将最后的‘ ’去掉
vs.push_back(tmpstr);
return ;
}
int start = vi[cur];
for(int i = cur + 1; i < vi.size(); i++){//此处的循环为了找到两个有效的开始下标,
string str = tmpstr;
//检查两个开始下标之间的单词是否在字典中
if(dict.find(s.substr(start, vi[i] - start)) != dict.end()){
str = tmpstr + s.substr(start, vi[i] - start);
str.push_back(' ');
collectStr(s, str, vi, i, vs, dict);
}
}
}
vector<string> wordBreak(string s, unordered_set<string> &dict) {
size_t n = s.size();
vector<string> vs;
if(n == 0) return vs;
vector<bool> vb(n + 1, false);
vb[n] = true;
for(int i = n - 1; i >= 0; i--){
for(unordered_set<string>::iterator itor = dict.begin(); itor != dict.end(); itor++){
int dwordlen = itor->size(); //字典中单词的长度
int tlen = n - i; //当前要查找的字符串位置 到末尾的距离
if(tlen >= dwordlen && !vb[i]){
//一定要保证在i + dwordlen之前的字符串可以查找到
if(vb[i + dwordlen] && s.substr(i, dwordlen) == *itor){
vb[i] = true; break;
}
}
}
}
vector<int> vi; //技巧处,将每次查找到的单词开始位置保存起来
//因为所有有效的单词必然在两个开始下标之间,所以单独存处,递归时比较方便
if(vb[0]){
for(int i = 0; i < n + 1; i++){
if(vb[i]) vi.push_back(i);
}
}
string tmpstr;
if(vi.size() <= 1) return vs;
collectStr(s, tmpstr, vi, 0, vs, dict);
return vs;
}
};