2022-5-23[字典树] 添加与搜索单词,搜索推荐系统,数组中两个数的最大异或值,与数组中元素的最大异或值

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

请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。

实现词典类 WordDictionary

  • WordDictionary() 初始化词典对象
  • void addWord(word)word 添加到数据结构中,之后可以对它进行匹配
  • bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。
Example 1
输入:
["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
输出:
[null,null,null,null,false,true,true,true]

解释:
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
wordDictionary.search("pad"); // 返回 False
wordDictionary.search("bad"); // 返回 True
wordDictionary.search(".ad"); // 返回 True
wordDictionary.search("b.."); // 返回 True
Example 2
输入:
["WordDictionary","addWord","addWord","addWord","addWord","search","search","addWord","search","search","search","search","search","search"]
[[],["at"],["and"],["an"],["add"],["a"],[".at"],["bat"],[".at"],["an."],["a.d."],["b."],["a.d"],["."]]
输出:
[null,null,null,null,null,false,false,null,true,true,false,false,true,false]
代码
struct Trie {
    bool isEnd;
    vector<Trie *> children;

    Trie() : isEnd(false), children(26, nullptr) {};
};

class WordDictionary {
private:
    Trie *root;

    bool searchWord(string &word, int iStart, Trie *node) {
        for (int i = iStart; i < word.size(); ++i) {
            if (word[i] == '.') {
                return any_of(node->children.begin(), node->children.end(), [&](Trie *next) {
                    return next != nullptr && searchWord(word, i + 1, next);
                });
            } else if (!node->children[word[i] - 'a']) {
                return false;
            } else {
                node = node->children[word[i] - 'a'];
            }
        }
        return node->isEnd;
    }

public:
    WordDictionary() {
        root = new Trie();
    }

    void addWord(string word) {
        auto node = root;
        for (char ch:word) {
            if (!node->children[ch - 'a']) node->children[ch - 'a'] = new Trie();
            node = node->children[ch - 'a'];
        }
        node->isEnd = true;
    }

    bool search(string word) {
        return searchWord(word, 0, root);
    }
};

2. 搜索推荐系统

给你一个产品数组 products 和一个字符串 searchWordproducts 数组中每个产品都是一个字符串。

请你设计一个推荐系统,在依次输入单词 searchWord 的每一个字母后,推荐 products 数组中前缀与 searchWord 相同的最多三个产品。如果前缀相同的可推荐产品超过三个,请按字典序返回最小的三个。

请你以二维列表的形式,返回在输入 searchWord 每个字母后相应的推荐产品的列表。

Example 1
输入:products = ["mobile","mouse","moneypot","monitor","mousepad"], searchWord = "mouse"
输出:[
["mobile","moneypot","monitor"],
["mobile","moneypot","monitor"],
["mouse","mousepad"],
["mouse","mousepad"],
["mouse","mousepad"]
]
解释:按字典序排序后的产品列表是 ["mobile","moneypot","monitor","mouse","mousepad"]
输入 m 和 mo,由于所有产品的前缀都相同,所以系统返回字典序最小的三个产品 ["mobile","moneypot","monitor"]
输入 mou, mous 和 mouse 后系统都返回 ["mouse","mousepad"]
Example 2
输入:products = ["havana"], searchWord = "havana"
输出:[["havana"],["havana"],["havana"],["havana"],["havana"],["havana"]]
代码
struct Trie {
    bool isEnd;
    vector<Trie *> children;
    string word;

    Trie() : isEnd(false), children(26, nullptr), word() {};
};


class Solution {
private:
    Trie *root;

    void addWord(string &s) {
        auto node = root;
        for (char ch:s) {
            if (!node->children[ch - 'a']) node->children[ch - 'a'] = new Trie();
            node = node->children[ch - 'a'];
        }
        node->word = s;
        node->isEnd = true;
    }

    Trie *searchPrefix(string &s, int end) {  // s[0,end)
        auto node = root;
        for (int i = 0; i < s.size() && i < end; i++) {
            if (!node->children[s[i] - 'a']) return nullptr;
            node = node->children[s[i] - 'a'];
        }
        return node;
    }

    void dfs(Trie *node, vector<string> &path) {
        if (!node) return;
        if (path.size() == 3) return;
        if (node->isEnd) path.emplace_back(node->word);
        for (int i = 0; i < 26; i++) {
            if (node->children[i]) dfs(node->children[i], path);
        }
    }

public:
    vector<vector<string>> suggestedProducts(vector<string> &products, string searchWord) {
        root = new Trie();
        for (auto &s:products) addWord(s);
        int n = searchWord.size();
        vector<vector<string>> result;
        vector<string> path;
        for (int i = 0; i < n; i++) {
            path.clear();
            auto node = searchPrefix(searchWord, i + 1);
            dfs(node, path);
            result.emplace_back(path);
        }
        return result;
    }
};

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

给你一个整数数组 nums ,返回 nums[i] XOR nums[j] 的最大运算结果,其中 0 ≤ i ≤ j < n

**进阶:**你可以在 O(n) 的时间解决这个问题吗?

Example 1
输入:nums = [3,10,5,25,2,8]
输出:28
解释:最大运算结果是 5 XOR 25 = 28.
Example 2
输入:nums = [0]
输出:0
代码
struct Trie {
    vector<Trie *> children;
    Trie() : children(2, nullptr) {}
};

class Solution {
private:
    Trie *root;

    void addNumber(int num) {
        auto node = root;
        for (int i = 30, bit; i >= 0; i--) {
            bit = (num >> i) & 1;
            if (!node->children[bit]) node->children[bit] = new Trie();
            node = node->children[bit];
        }
    }

    int maxXOR(int num) {
        int ans = 0;
        auto node = root;
        for (int i = 30, bit; i >= 0; i--) {
            bit = (num >> i) & 1;
            if (node->children[1 - bit]) {
                ans = 2 * ans + 1;
                node = node->children[1 - bit];
            } else {
                ans *= 2;
                node = node->children[bit];
            }
        }
        return ans;
    }

public:
    int findMaximumXOR(vector<int> &nums) {
        root = new Trie();
        int ans = 0;
        for (int num:nums) {
            addNumber(num);
            ans = max(ans, maxXOR(num));
        }
        return ans;
    }
};

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

给你一个由非负整数组成的数组 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.lengthanswer[i] 是第 i 个查询的答案。

Example 1
输入:nums = [0,1,2,3,4], queries = [[3,1],[1,3],[5,6]]
输出:[3,3,7]
解释:
1) 0 和 1 是仅有的两个不超过 1 的整数。0 XOR 3 = 3 而 1 XOR 3 = 2 。二者中的更大值是 3 。
2) 1 XOR 2 = 3.
3) 5 XOR 2 = 7.
Example 2
输入:nums = [5,2,4,6,6,3], queries = [[12,4],[8,1],[6,3]]
输出:[15,-1,5]
代码
struct Trie {
    vector<Trie *> children;

    Trie() : children(2, nullptr) {}
};

class Solution {
private:
    Trie *root;

    void addNumber(int num) {
        auto node = root;
        for (int i = 30, bit; i >= 0; i--) {
            bit = (num >> i) & 1;
            if (!node->children[bit]) node->children[bit] = new Trie();
            node = node->children[bit];
        }
    }

    int maxXOR(int num) {
        int ans = 0;
        auto node = root;
        for (int i = 30, bit; i >= 0; i--) {
            bit = (num >> i) & 1;
            if (node->children[1 - bit]) {
                ans = 2 * ans + 1;
                node = node->children[1 - bit];
            } else {
                ans *= 2;
                node = node->children[bit];
            }
        }
        return ans;
    }

public:
    vector<int> maximizeXor(vector<int> &nums, vector<vector<int>> &queries) {
        root = new Trie();
        vector<int> idx(queries.size());
        vector<int> result(queries.size(), -1);
        for (int i = 0; i < idx.size(); ++i) idx[i] = i;
        sort(idx.begin(), idx.end(), [&](int lo, int hi) {
            return queries[lo][1] < queries[hi][1];
        });
        sort(nums.begin(), nums.end());
        int i = 0, j = 0;
        while (j < idx.size() && nums[0] > queries[idx[j]][1]) j++;
        while (j < idx.size()) {
            while (i < nums.size() && nums[i] <= queries[idx[j]][1]) {
                addNumber(nums[i++]);
            }
            result[idx[j]] = maxXOR(queries[idx[j]][0]);
            j++;
        }
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值