題目140:單詞拆分II
說明:
分隔時可以重復使用字典中的單詞。
你可以假設字典中沒有重復的單詞。
示例1:
輸入:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
輸出:
[
"cats and dog",
"cat sand dog"
]
示例2:
輸入:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
輸出:
[
"pine apple pen apple",
"pineapple pen apple",
"pine applepen apple"
]
解釋: 注意你可以重復使用字典中的單詞。
示例3:
輸入:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
輸出:
[]
分析
可以動態(tài)規(guī)劃也可以回溯方法,這里還是使用回溯方法,但如果普通的回溯方法會超時,這里需要做一些優(yōu)化。
將輸入的wordDict的存儲的容易由vector變成set,優(yōu)化查詢速度
將wordDict中每個字符串的長度存儲到set中,回溯過程中字符串只截取set中有的長度,避免不必要的字符串截取
將每次回溯計算的結果存儲下來,避免不必要的遞歸操作
代碼
class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
GeneSets(wordDict); // vector convert to set
return BackTrace(s, 0);
}
vector<string> BackTrace(string &s, int idx) {
if (maps.find(idx) != maps.end()) { // 避免不必要的遞歸
return maps[idx];
}
int s_size = s.size();
vector<string> ret;
if (idx == s_size) {
ret.emplace_back("");
return ret;
}
for (int i = min_len; i <= max_len; ++i) {
if (idx + i > s_size) { break; }
// 避免不必要的字符串截取
if (len_sets.find(i) == len_sets.end()) { continue; }
string tem = s.substr(idx, i);
if (str_sets.find(tem) != str_sets.end()) {
vector<string> tem_ret = BackTrace(s, idx + i);
maps[idx+i] = tem_ret; // 保存每次計算的結果
for (auto &tem_str : tem_ret) {
string ss = (tem_str == "") ? "" : (" " + tem_str);
ret.emplace_back(tem + ss);
}
}
}
return ret;
}
map<int, vector<string>> maps;
set<string> str_sets;
set<int> len_sets;
int min_len = INT_MAX;
int max_len = 0;
void GeneSets(vector<string>& wordDict) {
for (auto &s : wordDict) {
int size = s.size();
min_len = min(min_len, size);
max_len = max(max_len, size);
str_sets.emplace(s);
len_sets.emplace(size);
}
}
};
