LeetCode 421 数组中两个数的最大异或值[前缀树 字典树] HERODING的LeetCode之路

在这里插入图片描述在这里插入图片描述

解题思路:
看到题目,一时半会没有思路,只好暴力进行,时间O(n²),C++超时,Java勉强过,可能用例太少了吧,仔细想想O(n)可以用哈希表实现,哈希表O(1),但是枚举每个数的二进制数需要O(logn),所以最理想还是O(nlogn)的情况。
这里我又新学了一招,基于前缀树的字典树,本质上就是二叉树,或者你可以理解为一种哈弗曼树,自上而下用二进制编码,我们把所有数的二进制存储进字典树中,然后遍历所有的数,在字典树中查找尽量相反的序列,时间复杂度也为O(nlongn),代码如下:

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

    void insert(int x)  // 在前缀树中插入值x
    {
        Trie *root = this;
        // 高位存储来Trie的前面,所以我们从左向右存储
        for(int i = 30; i >= 0; i --)
        {
            // 取第i位的数字,30...0
            int u = x >> i & 1;
            // 若第u位为空,则创建一个新节点,然后root移动到下一个节点
            if(!root->next[u]) root -> next[u] = new Trie();
            root = root -> next[u];
        }
    }

    int search(int x)  // 在前缀树中寻找 x 的最大异或值
    {
        Trie *root = this;
        // res表示最大异或值,每次res*2表示左移一位,31循环后左移了31位了,+u表示加上当前的最低位数字
        int res = 0;
        for(int i = 30; i >= 0;i --)
        {
            int u = x >> i & 1;
            // 若 x 的第 u 位存在,我们走到相反的方向去,因为异或总是|值|相反才取最大值的
            if(root -> next[!u]) root = root->next[!u], res = res * 2 + !u;
            // 相反方向的节点为空,只能顺着相同方向走了
            else root = root->next[u], res = res * 2 + u;
        }
        // 由于上面我们得到的异或另一个数组元素,此时我们需要将这个数组元素与x想异或得到 两个数的最大异或值
        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->search(x));
        return res;
    }
};

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

HERODING77

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

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

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

打赏作者

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

抵扣说明:

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

余额充值