超时:
class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
string tempResult="";
vector<string> result;
choose(s,0,tempResult,result,wordDict);
return result;
}
// s.substr(5, 3);
void choose(string s,int start,string tempResult,vector<string> &result,vector<string>& wordDict){
if(start==s.size()){
result.push_back(tempResult);
return;
}
for(int i=start;i<s.size();i++){
string t=s.substr(start,i-start+1);
string oldtemp=tempResult;
if(IsTrue(t,wordDict)){
if(i+1>=s.size()){
tempResult+=t;
}else{
tempResult+=t+" ";
}
choose(s,i+1,tempResult,result,wordDict);
tempResult=oldtemp;
}
}
}
// 判断这个t字串是否在字典wordDict中
bool IsTrue(string t,vector<string>& wordDict){
for(int i=0;i<wordDict.size();i++){
if(t==wordDict[i]) return true;
}
return false;
}
};
记忆化搜索:
这个题目如果直接使用递归,那么就会超时,因为递归时,从i的位置开始拆分的情况会被多次重复执行,所有我们需要纪录下每一个i开始的拆分可能,方便后面递归时重复使用。
class Solution {
public:
// 这个题目如果直接使用递归,那么就会超时,因为递归时,从i的位置开始拆分的情况会被多次重复执行,所有我们需要纪录下每一个i开始的拆分可能,方便后面递归时重复使用。
unordered_set<string> wordSet; // 这里定义一个集合,用来后面判断单词是否存在wordDict中
// result就比较重要了:result纪录每一个索引位置开始的单词拆分(多个可能)的vector
// result[start],表示从start开始单词拆分的可能性纪录
/****加入从start开始的第一个单词有3个字母,那么result[start]的结果为word加上result[start+3]的每一种可能
for(const string& item:result[i+3]){
result[start].push_back(word +item);
}
****/
unordered_map<int, vector<string>> result; // 纪录每个start开始划分的可能结果
vector<string> wordBreak(string s, vector<string>& wordDict) {
wordSet = unordered_set(wordDict.begin(), wordDict.end());
choose(s,0); // 从0开始拆分
return result[0];
}
void choose(string s,int start){
if (result.count(start)!=0) return; // 如果已有纪录不需往下执行
if(start==s.size()){
// 到最后位置
result[start]={
""};
return;
}
for(int i=start;i<s.size();++i){
string word=s.substr(start,i-start+1); // 拆分出一个单词
if(wordSet.count(word)){
choose(s,i+1); // 先递归一下后面的,不然下面下面就不能正确执行
for(const string& item:result[i+1]){
// 拼接
if(item=="") result[start].push_back(word +item);
else result[start].push_back(word +" "+item);
}
}
}
}
};