題目
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.
Gieve s = lintcode
,
dict = ["de", "ding", "co", "code", "lint"]
.
A solution is ["lint code",
"lint co de"]
.
解法
之前做了一道單詞切分的題目,直接深度優先搜索,超時後改成非遞歸形式的就過了,所以認爲這道題就是考深度優先搜索的。面對這個加強版的題也如法炮製,發現非遞歸形式也會超時,上網查了下才知道這題的核心是一個判斷字符串是否能被劃分的dp算法。
直接深度優先太慢,所以要先判斷一下排除掉不可能劃分的情況。dp[i] 表示從 i 開始到最後的子字符串可以被切分, len 表示字符串的長度。則有 dp[len] = true,當從 i 到 j 的字符串在字典中且 dp[j + 1] = true 時 dp[i] = true。有了這個表再進行深度優先搜索找出所有可能的劃分,不可能劃分的就不用算了。
vector<string> wordBreak(string s, unordered_set<string> &wordDict) {
// Write your code here
vector<bool> dp(s.size() + 1, true);
string dps;
for(int i = s.size() - 1; i >= 0; --i) {
dps.clear();
dp[i] = false;
for(int j = i; j < s.size(); ++j) {
dps.append(1, s[j]);
if(dp[j + 1] && wordDict.find(dps) != wordDict.end()) {
dp[i] = true; break;
}
}
}
vector<string> r;
vector<string> buf;
sub(s, wordDict, 0, buf, r, dp);
return r;
}
void sub(string& s, unordered_set<string> &dict, int cur, vector<string>& buf, vector<string>& r, vector<bool>& dp) {
string t;
if(cur >= s.size()) {
t = buf[0];
for(int i = 1; i < buf.size(); ++i) {
if(i > 0) t.append(1, ' ');
t.append(buf[i]);
}
r.push_back(t);
return;
}
if(!dp[cur]) return;
for(int i = cur; i < s.size(); ++i) {
t.append(1, s[i]);
if(dict.find(t) != dict.end()) {
buf.push_back(t);
sub(s, dict, i + 1, buf, r, dp);
buf.pop_back();
}
}
}