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"]
.
First, I used a similar algorithm as the one I used in problem Word Break I. However, I met Time Limit Exceeded error. The time complexity is o(n!). I realized I need to use more space to compensate the cost in time.
T(n) = \sum^n-1_(i = 1)(T(i)*T(n – 1))
Instead of storing path in dynamic programming array, I stored the last jump position in it. Finally, backtracking algorithm is used to retrieve the available path.
Reference: http://www.cnblogs.com/easonliu/p/3680966.html
Postorder DFS+DP
class Solution { public: vector<string> wordBreak(string s, unordered_set<string>& wordDict) { if(s.size() == 0 || wordDict.empty() == true) return vector<string>(); vector<int> dp[s.size()]; //store the last step of dp[i] for(int i = 0; i < s.size(); i++){ for(int j = i; j >= 0; j--){ string str = s.substr(j, i - j + 1); if(wordDict.find(str) != wordDict.end()){ //str exists in dict if(j == 0 || dp[j - 1].empty() == false){ // this line is important, dynamic programming should use previous elements in array. dp[i].push_back(j); } } } } string path; vector<string> paths; //retrieve the path retrievePath(s, dp, s.size() - 1, path, paths); return paths; } //backtracking void retrievePath(string s, vector<int> dp[], int pos, string path, vector<string>& paths){ //base condition if(pos == -1){ paths.push_back(path); } //backtracking else if(dp[pos].empty()){ return ; } else{ //ordinary condition if(pos != s.size() - 1){ //not the first step, path is not empty path.insert(0, " "); } for(auto it = dp[pos].begin(); it != dp[pos].end(); it++){ string newPath = path; newPath.insert(0, s.substr(*it, pos - *it + 1)); retrievePath(s, dp, *it - 1, newPath, paths); } } } };
Preorder DFS+DP
class Solution { public: vector<string> wordBreak(string s, unordered_set<string>& wordDict) { if(s.size() == 0) return vector<string>(); auto dp = vector<vector<int>>(s.size(), vector<int>()); for(int i = 0; i < s.size(); i++){ if(wordDict.count(s.substr(0, i+1)) > 0){ dp[i].push_back(0); } } for(int i = 0; i < s.size() - 1; i++){ if(!dp[i].empty()){ for(int j = i+1; j < s.size(); j++){ if(wordDict.count(s.substr(i+1, j - i)) > 0){ dp[j].push_back(i+1); } } } } return DFS(s, dp, s.size() - 1); } vector<string> DFS(string& s, vector<vector<int>>& dp, int pos){ // base condition vector<string> ans; if(pos < 0){ ans.push_back(""); return ans; } for(auto it = dp[pos].begin(); it!= dp[pos].end(); it++){ auto thisAns = DFS(s, dp, *it - 1); for(auto itthisAns = thisAns.begin(); itthisAns != thisAns.end(); itthisAns++){ if(!(*itthisAns).empty()) (*itthisAns).push_back(' '); (*itthisAns).append(s.substr(*it, pos - *it + 1)); ans.push_back(*itthisAns); } } return ans; } };