leetcode 单词拆分 中等_字典树

 

 

 

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;
    }
};