五月集训(第二十三日)字典树

一、211. 添加与搜索单词 - 数据结构设计

1.原题链接

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

2.题目描述

        请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。实现词典类 WordDictionary :WordDictionary() 初始化词典对象;void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配;bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 ‘.’ ,每个 . 都可以表示任何一个字母。

3.解题思路

        字典树的插入

4.源码

class TrieNode{
public:
    vector<TrieNode*> child;
    bool isWord;
    TrieNode() : child(26, nullptr), isWord(false) {};
    ~TrieNode() {
        for (auto c : child) delete c;
    }
};
class WordDictionary {
public:
    WordDictionary() {
        root = new TrieNode();
    }
    ~WordDictionary() {
        delete root;
    }
    void addWord(string word) {
        TrieNode* p = root;
        for (char c : word) {
            int i = c - 'a';
            if (!p->child[i])
                p->child[i] = new TrieNode();
            p = p->child[i];
        }
        p->isWord = true;
    }
    
    bool search(string word) {
        return match(word, root, 0);
    }
    
    bool match(string& word, TrieNode* p, int start) {
        if (!p) return false;
        if (start == word.size()) return p->isWord;
        char c = word[start];
        if (c != '.') {
            return match(word, p->child[c - 'a'], start + 1);
        } else {
            for (const auto& child : p->child) {
                if (match(word, child, start + 1))
                    return true;
            }
        }
        return false;
    }
private:
    TrieNode* root;
};

二、1268. 搜索推荐系统

1.原题链接

1268. 搜索推荐系统

2.题目描述

        给你一个产品数组 products 和一个字符串 searchWord ,products 数组中每个产品都是一个字符串。请你设计一个推荐系统,在依次输入单词 searchWord 的每一个字母后,推荐 products 数组中前缀与 searchWord 相同的最多三个产品。如果前缀相同的可推荐产品超过三个,请按字典序返回最小的三个。请你以二维列表的形式,返回在输入 searchWord 每个字母后相应的推荐产品的列表。

3.解题思路

        字典树

4.源码

struct PreTree{
    PreTree():tree(26),word_flag(0){
    }
    
    void add(string s){
        PreTree * node=this;
        for(int i=0;i<s.size();i++){
            if(node->tree[s[i]-'a']==nullptr){
                PreTree* new_node=new PreTree();
                node->tree[s[i]-'a']=new_node;
            }
            node = node->tree[s[i]-'a'];
        }
        node->word_flag=1;
    }
    
    void backtrace(PreTree*node){
        if(node==nullptr){
            return;
        }
        if(ans.size()==3){
            return;
        }
        if(node->word_flag==1){
            ans.push_back(tmp);
        }
        
        for(int i=0;i<26;i++){
            if(node->tree[i]){
                tmp+=(i+'a');
                backtrace(node->tree[i]);
                tmp.pop_back();
            }
        }
    }

    vector<string> search(string s){
        ans.clear();
        tmp.clear();
        PreTree * node=this;
        int i;
        for(i=0;i<s.size();i++){
            if(node->tree[s[i]-'a']==nullptr){
               return ans;
            }
            tmp+=(s[i]);
            node = node->tree[s[i]-'a'];
        }
        backtrace(node);
        return ans;
    }

    vector<PreTree*> tree;
    int word_flag;
    vector<string> ans;
    string tmp;
};

class Solution {
public:
    vector<vector<string>> suggestedProducts(vector<string>& products, string searchWord) {
        PreTree pt;
        for(auto s:products){
            pt.add(s);
        }
        vector<vector<string>> ans;
        for(int i=1;i<=searchWord.size();i++){
            vector<string> tmp=pt.search(searchWord.substr(0,i));
            ans.push_back(tmp);
        }
        return ans;
    }
};

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

1.原题链接

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

2.题目描述

        给你一个整数数组 nums ,返回 nums[i] XOR nums[j] 的最大运算结果,其中 0 ≤ i ≤ j < n 。进阶:你可以在 O(n) 的时间解决这个问题吗?

3.解题思路

        

4.源码

class Trie
{
private:
    Trie* next[2]={nullptr};
public:
    Trie(){}

    void insert(int x)  
    {
        Trie *root=this;
        for(int i=30;i>=0;i--)
        {
            int u=x>>i&1;
            if(!root->next[u])root->next[u]=new Trie();
            root=root->next[u];
        }
    }

    int srearch(int x)  
    {
        Trie *root=this;
        int res=0;
        for(int i=30;i>=0;i--)
        {
            int u=x>>i&1;
            if(root->next[!u])root=root->next[!u],res=res*2+!u;
            else root=root->next[u],res=res*2+u;
        }
        res^=x;
        return res;
    }
};

class Solution {
public:
    int findMaximumXOR(vector<int>& nums) {
        Trie *root=new Trie();
        for(auto x:nums)root->insert(x);
        int res=0;
        for(auto x:nums)
            res=max(res,root->srearch(x));
        return res;
    }
};

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

1.原题链接

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

2.题目描述

        给你一个由非负整数组成的数组 nums 。另有一个查询数组 queries ,其中 queries[i] = [xi, mi] 。第 i 个查询的答案是 xi 和任何 nums 数组中不超过 mi 的元素按位异或(XOR)得到的最大值。换句话说,答案是 max(nums[j] XOR xi) ,其中所有 j 均满足 nums[j] <= mi 。如果 nums 中的所有元素都大于 mi,最终答案就是 -1 。返回一个整数数组 answer 作为查询的答案,其中 answer.length == queries.length 且 answer[i] 是第 i 个查询的答案。

3.解题思路

        字典树插入

4.源码

class Trie {
public:
    const int L = 30;

    Trie* children[2] = {};

    void insert(int val) {
        Trie* node = this;
        for (int i = L - 1; i >= 0; --i) {
            int bit = (val >> i) & 1;
            if (node->children[bit] == nullptr) {
                node->children[bit] = new Trie();
            }
            node = node->children[bit];
        }
    }

    int getMaxXor(int val) {
        int ans = 0;
        Trie* node = this;
        for (int i = L - 1; i >= 0; --i) {
            int bit = (val >> i) & 1;
            if (node->children[bit ^ 1] != nullptr) {
                ans |= 1 << i;
                bit ^= 1;
            }
            node = node->children[bit];
        }
        return ans;
    }
};

class Solution {
public:
    vector<int> maximizeXor(vector<int> &nums, vector<vector<int>> &queries) {
        sort(nums.begin(), nums.end());
        int numQ = queries.size();
        for (int i = 0; i < numQ; ++i) {
            queries[i].push_back(i);
        }
        sort(queries.begin(), queries.end(), [](auto &x, auto &y) { return x[1] < y[1]; });

        vector<int> ans(numQ);
        Trie* t = new Trie();
        int idx = 0, n = nums.size();
        for (auto &q : queries) {
            int x = q[0], m = q[1], qid = q[2];
            while (idx < n && nums[idx] <= m) {
                t->insert(nums[idx]);
                ++idx;
            }
            if (idx == 0) {
                ans[qid] = -1;
            } else {
                ans[qid] = t->getMaxXor(x);
            }
        }
        return ans;
    }
};

总结

        第二十三天,一天比一天难。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枏念

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值