421. Maximum XOR of Two Numbers in an Array(medium)

  1. Maximum XOR of Two Numbers in an Array
    Given an integer array nums, return the maximum result of nums[i] XOR nums[j], where 0 ≤ i ≤ j < n.
    Follow up: Could you do this in O(n) runtime?
    Example 1:
    Input: nums = [3,10,5,25,2,8]
    Output: 28
    Explanation: The maximum result is 5 XOR 25 = 28.
    Constraints:
    1 <= nums.length <= 2 * 104
    0 <= nums[i] <= 231 - 1

这道题难住我了,完全没有思路。看了题目标签有trie,依旧没有思路。看官方题解第一遍看不懂。

反思一下,对于树(包括前缀树)很陌生,位运算很陌生,贪心算法也很陌生,需要练习这三类题。

1.哈希表
数值最大是231-1,即二进制共31位,高位到低位依次编号为30~0
令结果为x,对于结果的每一位,从高到低依次判断是否能为1(此处有贪心思想)。如果已经判定了k-1位,首先假设k位可以为1,则x_next=(x>>1)+1, 由x(k)=nums[i](k) ^ nums[j](k)==> nums[j](k) =nums[i](k) ^ x(k) ,可知,如果此时的x_next满足要求,则一定存在一个数,前k位和x_next异或,结果也是nums的某一个数的前k位。实现这部分的方式是,使用集合存储nums数组中每个数的前k位,然后依次枚举nums中的每个数,判断num^x_next是否在集合中,如果在,说明第k位可以是1,否则第k位是0.
最后返回x

    int findMaximumXOR(vector<int>& nums) {
        if(nums.size()==1){
            return 0;
        }
        int x=0;
        for(int k=30;k>=0;k--){
            unordered_set<int>pre;
            bool found=false;
            for(auto num:nums){
                pre.insert(num>>k);
            } 
            int x_next=(x<<1)+1;
            for(auto num:nums){
                if(pre.count((num>>k)^(x_next))){
                    found=true;
                    break;
                }
            }
            if(!found){
                x_next-=1;
            }
            x=x_next;
        }
        return x;
    }

2.前缀树
使用前缀树保存nums中的每一个数据,对于nums[i],前i-1个数已经存储在前缀树中。从根节点向下遍历前缀树。由0^1=1,如果num第k位是0,要想x尽可能大,应该选择第k+1层的右节点;如果num第k位是1,应该选择第k+1层的左节点,
细节:取第k位时,num>>k之后,要&1
前缀树中,root节点以下共31层数值节点,k==30时,cur=root。对于k,cur指向第k+1层

struct Trie{
    Trie *left=nullptr;
    Trie *right=nullptr;
    Trie(){};
};
class Solution {
private:
    Trie *root=new Trie();

public:
    void add(int num){
        Trie *cur=root;
        for(int k=30;k>=0;k--){
            int bit=(num>>k)&1;
            if(bit==0){
                if(!cur->left){
                    cur->left=new Trie();
                }
                cur=cur->left;
            }else{
                if(!cur->right){
                    cur->right=new Trie();
                }
                cur=cur->right;
            }
        }
    }
    int check(int num){
        int x=0;
        Trie *cur=root;
        for(int k=30;k>=0;k--){
            int bit=(num>>k)&1;
            int x_next=x<<1;
            if(bit==0){
                if(cur->right){
                    x_next+=1;
                    cur=cur->right;
                }else{
                    cur=cur->left;
                }
            }else{
                if(cur->left){
                    x_next+=1;
                    cur=cur->left;
                }else{
                    cur=cur->right;
                }
            }
            x=x_next;
        }
        return x;
    }
    int findMaximumXOR(vector<int>& nums) {
        int x=0;
        for(int i=1;i<nums.size();i++){
            add(nums[i-1]);
            x=max(x,check(nums[i]));
        }
        return x;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值