dp,dp[i] 表示从 0 到下标 i 是否能够拆分
状态转移也不困难:假设当前 i 能够拆分,枚举 wordDict,如果 [i + 1, i + wordDict[j].size()] 与 wordDict[j] 相等,那么 dp[i + wordDict[j].size()] = true
然后就是快速判断相等,可以用 hash 来做。
这里是手写 hash。官方的答案里面用的 unordered_set,但是使用 s.substr(),这个应该是 O(n) 吧???
class Solution { public: bool wordBreak(const string &s, vector<string>& wordDict) { vector<ull> hashs{0}, powHash; for(int i = 0; i < s.size(); ++ i) { if(i == 0) { hashs.emplace_back(s[i]); powHash.emplace_back(1); } else { hashs.emplace_back(hashs.back() * base + s[i]); powHash.emplace_back(powHash.back() * base); } } powHash.emplace_back(powHash.back() * base); // 第一个值得注意的点, ! vector<ull> hashWD; for(int i = 0; i < wordDict.size(); ++ i) { ull hashx = 0; for(int j = 0; j < wordDict[i].size(); ++ j){ hashx = hashx * base + wordDict[i][j]; } hashWD.emplace_back(hashx); } vector<bool> dp(s.size() + 1, false); dp[0] = true; // dp, hashs 整体下标向右偏移 1 个单位. 第二个值得注意的点。 for(int i = 0; i < s.size(); ++ i) { for(int j = 0; j < wordDict.size(); ++ j) { int len = (int)wordDict[j].size(); if(i - len + 1 < 0 || !dp[i - len + 1]) continue; if(hashWD[j] == hashs[i + 1] - hashs[i - len + 1] * powHash[len]) { dp[i + 1] = true; break; } } } return dp.back(); } typedef unsigned long long ull; ull base = 131; };
也可以用字典树:
class Solution { public: bool wordBreak(const string &s, vector<string>& wordDict) { for(int i = 0; i < wordDict.size(); ++ i) { insert(wordDict[i]); } vector<bool> dp(s.size(), false); for(int i = 0; i < s.size(); ++ i) { if(i == 0 || dp[i - 1]) { int p = 0; for(int j = i; j < s.size(); ++ j) { if(!trie[p][s[j] - 'a']) break; p = trie[p][s[j] - 'a']; if(tag[p]) dp[j] = true; } } } return dp.back(); } static const int maxn = 2e5 + 10; int trie[maxn][26]; bool tag[maxn]; int k = 1; // 使用结点 void insert(const string &s) { int p = 0; for(int i = 0; i < s.size(); ++ i) { int temp = s[i] - 'a'; if(!trie[p][temp]) trie[p][temp] = k ++; p = trie[p][temp]; } tag[p] = true; } };