力扣-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]; } };
加上剪枝,情况好了很多
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/16903003.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步