作用:Trie是一种用于元素范围较小(如0/1,26个字母),常用于字符串前缀、异或值相关的

原理:前缀树,每个节点有固定的sigma个节点,同一层是元素们的同一pos。

实现:

非动态开点

leetcode 1707. 与数组中元素的最大异或值

思路:先排序,再只把小于等于limit的加入,再求该元素与数组元素的最大值。

class Solution {
public:
    #define maxnode 32*100000+10
    #define sigma 2
    struct Trie {
        int ch[maxnode][sigma];
        int value[maxnode]; //  叶子节点的值
        int cnt[maxnode];   // 经该节点的元素个数
        int sz = 1;

        void init(){
            memset(ch, 0 ,sizeof(ch));
            memset(cnt, 0, sizeof(cnt));
            memset(value, 0, sizeof(value));
        }
    
        void insert(int x){
            int u = 0;
            for(int i = 31; i >= 0; i--){
                int c = (x>>i)&1;
                if(!ch[u][c])  ch[u][c] = sz++;
                u = ch[u][c];
                cnt[u]++;
            }
            value[u] = x;
        }

        // 查询与x异或的最大值
        int query(int x){
            int u = 0, res = 0;
            for(int i = 31; i >= 0; --i){
                int a = (x>>i)&1;
                // cout << a << " " << b << endl;
                if(ch[u][a^1])  u = ch[u][a^1];
                else  u = ch[u][a];
            }
            return value[u]^x;
        }
    }trie;
    struct Node {
        int x, limit, id;
        Node(int x, int limit, int id) : x(x), limit(limit), id(id) {}
        bool operator < (const Node& node) {
            return this->limit < node.limit;
        }
    };

    vector<int> maximizeXor(vector<int>& nums, vector<vector<int>>& queries) {
        sort(nums.begin(), nums.end());
        vector<Node>myqueries;
        for(int i = 0;i < queries.size();i++) {
            myqueries.push_back(Node(queries[i][0], queries[i][1], i));
        }
        sort(myqueries.begin(), myqueries.end());
        trie.init();
        vector<int>res(queries.size());
        int pos = 0;  // nums数组的当前位置
        for(auto query : myqueries) {
            int x = query.x, limit = query.limit, id = query.id;
            // cout << x << " " << limit << " " << id << endl;
            while(pos < nums.size() && nums[pos] <= limit)  trie.insert(nums[pos++]);
            //  cout << "pos: " << pos << endl;
            if(pos == 0)  res[id] = -1;
            else  res[id] = trie.query(x);
           
            
        }
        return res;
    }
};

动态开点

leetcode211. 添加与搜索单词 - 数据结构设计

思路:动态开点,用节点指针。遇到 通配符‘.’ 进行dfs

class WordDictionary {
public:
    /** Initialize your data structure here. */
    struct Node {
        Node* son[26];
        bool is_end;
        Node(){
            for(int i = 0;i < 26;i++)  son[i] = NULL;
            is_end = false;
        }
    };
    // static Node* root;
    struct Trie {
        Node* root;
        void init(){
            root = new Node();
        }
    
        void insert(string str){
            Node* p = root;
            for(char mych : str){
                int c = mych-'a';
                if(!p->son[c])  p->son[c] = new Node();
                p = p->son[c];
            }
            // value[u] = str;
            p->is_end = true;
        }

        // 查询str是否存在
        bool query(string str, int pos, Node* p){
            // cout << str << " " << pos << " " << u << endl;
            if(pos == str.size())  return p->is_end;
            char mych = str[pos];
            if(mych == '.') {
                for(int i = 0;i < 26;i++) {
                    if(p->son[i] && query(str, pos+1, p->son[i]))  return true;
                }
                return false;
            } else {
                int c = mych-'a';
                if(!p->son[c])  return false;
                else {
                    return query(str, pos+1, p->son[c]);
                }
            }
        }
    }trie;

    WordDictionary() {
        trie.init();
    }
    
    void addWord(string word) {
        trie.insert(word);
    }
    
    bool search(string word) {
        return trie.query(word, 0, trie.root);
    }
};

其他的一些例子:

leetcode 745. 前缀和后缀搜索

思路:插入的时候加trick,并给每个节点更新权重,查询还是普通查询

class WordFilter {
public:

    struct Node {
        Node* son[27];
        int weight;
        Node(){
            for(int i = 0;i < 27;i++)  son[i] = NULL;
            weight = -1;
        }
    };
    // static Node* root;
    struct Trie {
        Node* root;
        void init(){
            root = new Node();
        }
    
        void insert(string str, int index){
            Node* p = root;
            for(char mych : str){
                int c;
                if(mych == '#')  c = 26;
                else  c = mych-'a';
                if(!p->son[c])  p->son[c] = new Node();
                p = p->son[c];
                p->weight = max(index, p->weight);  // 每个节点都要个更新
            }
            // value[u] = str;
        }

        // 查询str子串的权重
        int query(string str){
            int n = str.size();
            Node* p = root;
            for(int i = 0;i < n;i++) {
                int c;
                if(str[i] == '#')  c = 26;
                else  c = str[i]-'a';
                if(!p->son[c])  return -1;
                p = p->son[c];
            }
            return p->weight;
        }
    }trie;

    WordFilter(vector<string>& words) {
        trie.init();
        for(int i = 0;i < words.size();i++) {
            string suf = "";
            string word = words[i];
            int n = word.size();
            for(int j = 0;j <=n;j++) {
                // cout << suf+'#'+word  << endl;
                trie.insert(suf+'#'+word, i);
                if(j!=n) suf = word[n-1-j] + suf;
            }  
        }
    }
    
    int f(string prefix, string suffix) {
        string word = suffix + '#' + prefix;
        return trie.query(word);
    }

};

/**
 * Your WordFilter object will be instantiated and called as such:
 * WordFilter* obj = new WordFilter(words);
 * int param_1 = obj->f(prefix,suffix);
 */
View Code

相关文章: