字典树及相关问题


字典树模板题

LeetCode 208. 实现Trie(前缀树)

class Trie {
public:
    /** Initialize your data structure here. */
    Trie() {
        isEnd = false;
        fill(begin(next), end(next), nullptr);
    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        Trie* curr = this;
        for(auto ch : word){
            if(curr->next[ch-'a'] == nullptr){
                curr->next[ch-'a'] = new Trie();
            }
            curr = curr->next[ch-'a'];
        }
        curr->isEnd = true;
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        Trie* curr = this;
        for(auto ch : word){
            if(curr->next[ch-'a'] == nullptr){
                return false;
            }
            curr = curr->next[ch-'a'];
        }
        return curr->isEnd;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        Trie* curr = this;
        for(auto ch : prefix){
            if(curr->next[ch-'a'] == nullptr){
                return false;
            }
            curr = curr->next[ch-'a'];
        }
        return true;
    }
private:
    static const int R = 26;
    Trie* next[R];
    bool isEnd;
};

LeetCode 1032. 字符流
反向建树

class Trie {
public:
    Trie(){
        isEnd = false;
        fill(begin(next), end(next), nullptr);
    }
        
    void insert(const string& word){
        Trie* curr = this;
        for(auto ch=word.rbegin();ch!=word.rend();++ch){
            if(curr->next[*ch-'a'] == nullptr){
                curr->next[*ch-'a'] = new Trie();
            }
            curr = curr->next[*ch-'a'];
        }
        curr->isEnd = true;
    }
        
    bool query(const string& word){
        Trie* curr = this;
        for(auto ch=word.rbegin();ch!=word.rend();++ch){
            if(curr->next[*ch-'a'] != nullptr){
                curr = curr->next[*ch-'a'];
                if(curr->isEnd) return true;
            }else return false;
        }
        return false;
    }
private:     
    static const int R = 26;
    Trie* next[R];
    bool isEnd;
};

class StreamChecker {
public:
    StreamChecker(vector& words) {
        trie = new Trie();
        for(auto& word : words){
            trie->insert(word);
        }
    }
    
    bool query(char letter) {
        buffer.push_back(letter);
        return trie->query(buffer);
    }
private:
    Trie* trie;
    string buffer;
};

/**
 * Your StreamChecker object will be instantiated and called as such:
 * StreamChecker* obj = new StreamChecker(words);
 * bool param_1 = obj->query(letter);
 */

LeetCode 745. 前缀和后缀搜索
对于每个单词,将它所有可能的后缀、分隔符以及单词本身插入到字典树中,同时记录一下这些单词的权重。在查询阶段,可以通过将后缀、分隔符和前缀组合成一个单词进行查询,返回对应的权重即可。例如,对于单词test,我们将test#test,est#test,st#test,t#test以及#test插入到字典树中。在查询时,假如遇到前缀te和后缀t,那么就将它们组合成t#te进行查询。

字典树+DFS

LeetCode 211. 添加与搜索单词

class WordDictionary {
public:
    /** Initialize your data structure here. */
    WordDictionary() {
        isEnd = false;
        fill(begin(next), end(next), nullptr);
    }
    
    /** Adds a word into the data structure. */
    void addWord(string word) {
        WordDictionary* curr = this;
        for(auto ch : word){
            if(curr->next[ch-'a'] == nullptr){
                curr->next[ch-'a'] = new WordDictionary();
            }
            curr = curr->next[ch-'a'];
        }
        curr->isEnd = true;
    }
    
    /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
    bool search(string word) {
        return search(word.begin(), word.end(), this);
    }
private:
    bool isEnd;
    static const int R = 26;
    WordDictionary* next[R];
    
    template
    bool search(ForwardIt first, ForwardIt last, WordDictionary* root){
        if(first == last) return root->isEnd;
        if(*first == '.'){
            for(int i=0;i < R;++i){
                if(root->next[i] != nullptr && search(first+1, last, root->next[i])) return true;
            }
        }else if(root->next[*first-'a'] != nullptr){
            return search(first+1, last, root->next[*first-'a']);
        }
        return false;
    }
};

/**
 * Your WordDictionary object will be instantiated and called as such:
 * WordDictionary* obj = new WordDictionary();
 * obj->addWord(word);
 * bool param_2 = obj->search(word);
 */

LeetCode 677. 键值映射

class MapSum {
public:
    /** Initialize your data structure here. */
    MapSum() {
        val = 0;
        isEnd = false;
    }
    
    void insert(string key, int val) {
        MapSum* curr = this;
        
        for(auto ch : key){
            if(curr->next.count(ch) == 0){
                curr->next.insert({ch, new MapSum()});
            }
            curr = curr->next[ch];
        }
        curr->val = val;
        curr->isEnd = true;
    }
    
    int sum(string prefix) {
        MapSum* curr = this;
        int ans = 0;
        for(auto ch : prefix){
            if(curr->next.count(ch) == 0){
                return ans;
            }
            curr = curr->next[ch];
        }
        return dfs(curr);
    }
private:
    unordered_map next;
    int val;
    int isEnd;
    
    int dfs(MapSum* root){
        int sum = 0;
        for(auto it : root->next){
            if(it.second != nullptr){
                sum += dfs(it.second);
            }
        }
        if(root->isEnd) sum += root->val;
        return sum;
    }
};

/**
 * Your MapSum object will be instantiated and called as such:
 * MapSum* obj = new MapSum();
 * obj->insert(key,val);
 * int param_2 = obj->sum(prefix);
 */

LeetCode 820. 单词的压缩编码
反向建树+DFS

class Trie {
public:
    Trie() {
        fill(begin(next), end(next), nullptr);
        isEnd = false;
    }
    
    void insert(string words) {
        Trie* curr = this;
        for(auto it = words.crbegin();it != words.crend(); ++it){
            if(curr->next[*it-'a'] == nullptr) {
                curr->next[*it-'a'] = new Trie();
            }
            curr = curr->next[*it-'a'];
        }
        curr->isEnd = true;
    }
    
    int count(Trie* root, int cnt) {
        bool isLeaf = true;
        int sum = 0;
        for(int i = 0;i < R;++i) {
            if(root->next[i] != nullptr) {
                isLeaf = false;
                sum += count(root->next[i], cnt+1);
            }
        }
        return isLeaf ? cnt + 1 : sum;
    }
private:
    static const int R = 26;
    Trie* next[R];
    bool isEnd;
};

class Solution {
public:
    int minimumLengthEncoding(vector& words) {
        Trie* trie = new Trie();
        for(const auto& it : words) {
            trie->insert(it);
        }
        int ans = trie->count(trie, 0);
        return ans ;
    }
};

LeetCode 421. 数组中两个数的最大异或值