Leetcode 140. Word Break II

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

method 1 backtracking

附上一個TLE的反面案例
超時的原因在於,許多子字符串的分割重複,每次傳入的都是原來的字符串,再加上一個start指示開始索引
一般情況下都是可以通過的,但當遇到極端case諸如 aaaaaaaaaaaaaaa和[a,aa,aaa,aaaa,aaaaa]這樣的,會導致大量的重複計算,最後導致超時
對於超時有兩點體會

  1. 引入dp
  2. 每次傳入時,傳入新的截取過後的字符串,更容易分析
void helper(vector<string>& ans, string s, int start, vector<string>& wordDict, string tmp){
	if (start == s.size()){
		ans.push_back(tmp.substr(1, tmp.size() - 1));
	}
	else{
		for (int i = start; i < s.size(); i++)
		{
			string left = s.substr(start, i - start + 1);
			if (find(wordDict.begin(), wordDict.end(), left) != wordDict.end()){
				helper(ans, s, i + 1, wordDict, tmp + " " + left);
			}
		}
	}
}

vector<string> wordBreak(string s, vector<string>& wordDict) {
	vector<string> ans;
	if (wordDict.size() == 0) return ans;

	helper(ans, s, 0, wordDict, "");
	return ans;
}

method 2 dynamic programming

引入dp, 記錄字符串s對應的所有句子,因爲在回溯過程中,會出現重複的分支,在正常輸入下,基本不會出現重複的分支,但比如aaaaaaaaa,[a,aa,aaa,aaaa]這樣的,就會導致許多重複分支,所有使用dp記錄下來,遇到合適的字符串,直接返回其ans

  1. 雖然自己用dp嘗試過,但思路不對,只是簡單想着某一個substr是否出現過,如果出現過,還是對其遞歸回溯,應該進一步想,如果出現過,直接記錄其結果
  2. 沒有找到重複最多的部分進行優化
  3. 畫出解答樹優化
unordered_map<string, vector<string>> m;

    vector<string> combine(string word, vector<string> prev){
        for(int i=0;i<prev.size();++i){
            prev[i]+=" "+word;
        }
        return prev;
    }
    
    vector<string> wordBreak(string s, vector<string>& wordDict) {
	if (m.count(s)) return m[s]; //take from memory
	vector<string> result;
	if (find(wordDict.begin(), wordDict.end(), s) != wordDict.end()){ //a whole string is a word
		result.push_back(s);
	}
	for (int i = 1; i<s.size(); ++i){
		string word = s.substr(i);
		if (find(wordDict.begin(), wordDict.end(), word) != wordDict.end()){
			string rem = s.substr(0, i);
			vector<string> prev = combine(word, wordBreak(rem, wordDict));
			result.insert(result.end(), prev.begin(), prev.end());
		}
	}
	m[s] = result; //memorize
	return result;
}

summary

  1. 遞歸回溯傳入時,傳入新的截取過後的字符串,更容易分析
  2. 要對重複最多的部分進行優化
  3. 可以選取TLE的case,畫出解答樹,從而找到重複最多的部分,正確的引入dynamic programming解決問題
發佈了93 篇原創文章 · 獲贊 9 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章