letecode 140
给定一个非空字符串 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"]
输出:
[]
解题方式可以采用dfs, 这里记录一下动态规划的算法
class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
if (!bcanBreak(s, wordDict)) return {};
size_t validEnd = 0;
vector<vector<string>> dp(s.size() + 1, vector<string>());
for (size_t i = 0; i < s.size(); i++) {
if (i == validEnd + 1) return {};
if (i != 0 && dp[i].empty()) continue;
for (auto& word : wordDict) {
size_t newEnd = i + word.size();
if (newEnd > s.size()) continue;
if (memcmp(&s[i], &word[0], word.size()) != 0) continue;
validEnd = max(validEnd, newEnd);
if (i == 0) {
dp[newEnd].push_back(word);
continue;
}
for (auto& d : dp[i]) {
dp[newEnd].push_back(d + " " + word);
}
}
}
return dp.back();
}
bool bcanBreak(string& s, vector<string>& wordDict) {
size_t validEnd = 0;
vector<bool> dp(s.size() + 1, false);
dp[0] = true;
for (size_t i = 0; i < s.size(); i++) {
if (i == validEnd + 1) return false;
if (!dp[i]) continue;
for (auto& word : wordDict) {
size_t newEnd = i + word.size();
if (newEnd > s.size()) continue;
if (memcmp(&s[i], &word[0], word.size()) == 0) {
dp[newEnd] = true;
validEnd = max(validEnd, newEnd);
}
}
}
return dp.back();
}
};
1.通过动态规划来计算当前的字符串是否可以按照字典被分割。(这可以将异常的先剔除,防止直接进入后面)。
2. 通过动态规划不断更新新的validEnd, 同时后面的newEnd的结果,可以利用前面的缓存的结果进行系能的提升。