leetcode#140 单词拆分II
题目:
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
- 分隔时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例:
输入:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
输出:
[
"cats and dog",
"cat sand dog"
]
思路:
第 139 题可以使用动态规划的方法判断是否可以拆分,因此这道题也可以使用动态规划的思想。但是这道题如果使用自底向上的动态规划的方法进行拆分,则无法事先判断拆分的可行性,在不能拆分的情况下会超时。
为了避免动态规划的方法超时,需要首先使用第 139 题的代码进行判断,在可以拆分的情况下再使用动态规划的方法进行拆分。相比之下,自顶向下的记忆化搜索可以在搜索过程中将不可以拆分的情况进行剪枝,因此记忆化搜索是更优的做法。
自顶向下,记忆化搜索,如果子问题搜索过了直接返回记下的句子集合,对于每个子问题,把他返回的句子加上当前截取的单词作为一个句子推进当前记录数组中。
代码:
class Solution
{
public:
int n;
unordered_set<string> mp;
unordered_map<int, vector<string>> ans;
void dfs(string s, int i)
{
if (!ans.count(i))
{
if (i == n)
{
ans[i].push_back({});
return;
}
for (int j = i; j < n; ++j)
{
string tmp = s.substr(i, j - i + 1);
if (mp.count(tmp))
{
dfs(s, j + 1);
for (auto k : ans[j + 1])
ans[i].push_back(k.empty() ? tmp : tmp + " " + k); //子问题搜索完后,把他的结果和当前单词结合推进当前答案数组中
}
}
}
}
vector<string> wordBreak(string s, vector<string> &wordDict)
{
n = s.length();
int size = wordDict.size();
for (int i = 0; i < size; ++i)
mp.insert(wordDict[i]);
dfs(s, 0);
return ans[0];
}
};
``