题目
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();
}
}
}