力扣-139-单词拆分
前缀树模板题?
直接看题解,明明是前缀树标签,却只给了动态规划
前缀树
我试图用208前缀树的直接思路解决这个问题
class Trie {
private:
vector<Trie*> children;
bool isEnd;
public:
Trie() :children(26), isEnd(false) {}
void insert(string word) {
Trie* node = this;
for (char ch : word) {
ch -= 'a';
if (node->children[ch] == nullptr)
node->children[ch] = new Trie();
node = node->children[ch];
}
node->isEnd = true;
}
bool wordBreak(string input) {
Trie* node = this;
for (int i = 0; i < input.length(); i++) {
input[i] -= 'a';
if (node->children[input[i]] == nullptr) return false;
node = node->children[input[i]];
if (node->isEnd && i != input.length() - 1)node = this;
}
return node->isEnd;
}
};
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
Trie trie;
for (string str : wordDict) trie.insert(str);
return trie.wordBreak(s);
}
};
但是卡在了这两个测试用例
"aaaaaaa"
["aaaa","aa"]
"aaaaaaa"
["aaaa","aaa"]
还是逃不掉动态规划吗
我又改成这样
bool wordBreak(string input,int start) {
Trie* node = this;
for (int i = start; i < input.length(); i++) {
input[i] -= 'a';
if (node->children[input[i]] == nullptr) return false;
node = node->children[input[i]];
if (node->isEnd && i != input.length() - 1)
if (wordBreak(input, i + 1))return true;
}
return node->isEnd;
}
然后被预判了,果断超时
动态规划
思路是判断i个位置,以strArr[i]结尾的字符串是否可以由状态转移方程递归出来
而每一次判断都需要从头遍历j位置,看以j做分隔的字符串能否由字典中的字符串构成
class Trie {
private:
vector<Trie*> children;
bool isEnd;
public:
Trie() :children(26), isEnd(false) {}
void insert(string word) {
Trie* node = this;
for (char ch : word) {
ch -= 'a';
if (node->children[ch] == nullptr)
node->children[ch] = new Trie();
node = node->children[ch];
}
node->isEnd = true;
}
bool search(string word) {
Trie* node = this;
for (char ch : word) {
ch -= 'a';
if (node->children[ch] == nullptr)
return false;
node = node->children[ch];
}
return node->isEnd;
}
};
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
Trie trie;
for (string str : wordDict) trie.insert(str);
int len = s.length();
vector<bool> dp(len + 1);
dp[0] = 1;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && trie.search(s.substr(j, i - j))) {
dp[i] = true;
break;
}
}
}
return dp[len];
}
};
自己写不如用现成的系列,本质还是动态规划,只是前缀树代替了set而已
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
Trie trie;
int maxLen = wordDict[0].length();
for (string str : wordDict) {
trie.insert(str);
if (str.size() > maxLen) maxLen = str.size();
}
int len = s.length();
vector<bool> dp(len + 1);
dp[0] = 1;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
// 剪枝:如果i-j的字符串长度已经大于了字典中最长字符串的长度
if (i - j > maxLen) continue;
if (dp[j] && trie.search(s.substr(j, i - j))) {
dp[i] = true;
break;
}
}
}
return dp[len];
}
};
加上剪枝,情况好了很多