139. 单词拆分
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成
解法一(前缀树)
具体做法是: 弄一个字典树Trie, 然后在Trie中做dfs。 dfs的定义是: bool dfs(string& s, int startPos), 表示在字符串s中开始搜索, 当前的搜索区间为 [startPos, s.size() - 1], 能搜索到就返回true, 否则false。
记忆化: 另外需要用个数组failMemo记录dfs没搜索到时对应的s中的index, 用bool或int数组都可以。
为什么做记忆化?
如果不做记忆化, 部分test case会TLE超时, 因为不做记忆化时会有挺多的重复判断。
class Tire{
public:
bool isEnd;
Tire* next[26];
Tire(){
isEnd = false;
for(int i = 0;i < 26;i++){
next[i] = nullptr;
}
}
};
class Solution {
public:
Tire* root;
int err_start[301];
bool wordBreak(string s, vector<string>& wordDict) {
root = new Tire();
//初始化前缀树
for(auto& word : wordDict){
Tire* p = root;
for(auto& c : word){
if(p->next[c-'a'] == nullptr){
p->next[c-'a'] = new Tire();
}
p = p->next[c-'a'];
}
p->isEnd = true;
}
return dfs(s,0);
}
bool dfs(string s,int start){
if(err_start[start] == 1) return false;
if(start == s.size()) return true;
//在前缀树中寻找
Tire* p = root;
for(int i = start;i < s.size();i++){
if(p->next[s[i] - 'a'] != nullptr){
p = p->next[s[i] - 'a'];
//只有该单词到达结尾 下一层dfs可以到达底层
if(p->isEnd && dfs(s,i+1)){
return true;
}
}else break;
}
err_start[start] = 1;
return false;
}
};
解法二(动态规划)
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
vector<bool> dp(s.size() + 1, false);
dp[0] = true;
for (int i = 1; i <= s.size(); i++) { // 遍历背包
for (int j = 0; j < i; j++) { // 遍历物品
string word = s.substr(j, i - j); //substr(起始位置,截取的个数)
if (wordSet.find(word) != wordSet.end() && dp[j]) {
dp[i] = true;
}
}
}
return dp[s.size()];
}
};
剪枝+优化
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
const int len = s.size();
vector<bool> dp(len + 1, false);
dp[0] = true;
for (int i = 1; i <= len; i++) { // 遍历背包
if(!dp[i-1]) continue;
for(auto& word:wordDict){
int j = i - 1 + word.size();
if(j <= len && s.substr(i - 1,word.size()) == word){
dp[j] = true;
}
}
}
return dp[len];
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理