题目140:单词拆分II
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
- 分隔时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例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"]
输出:
[]
分析
可以动态规划也可以回溯方法,这里还是使用回溯方法,但如果普通的回溯方法会超时,这里需要做一些优化。
- 将输入的wordDict的存储的容易由vector变成set,优化查询速度
- 将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);
}
}
};
网友评论