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

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

题目链接: https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array

这道题要找出给定列表中两个元素的最大异或值,这里采用字典树来写。

穷举法

要求给定列表任意两个元素的最大异或值,如果暴力做法,可以直接穷举两层列表中的各个元素。初始化结果为0,不断求得元素i和j的异或值,如果大于当前结果则更新当前结果为i,j的异或值。代码如下:

class Solution {
public:
    int findMaximumXOR(vector<int>& nums) {
        int maxXOR = 0;
        
        for(int i = 0; i < nums.size(); i++){
            for(int j = 0; j < nums.size(); j++){
                maxXOR = max(maxXOR, nums[i] ^ nums[j]);
            }
        }
        
        return maxXOR;
    }
};

这个做法两层遍历列表,其时间复杂度为O(N^2),空间复杂度为O(N)。显然,对于规模较大的数组,O(N^2)时间复杂度的算法是比较低效的,在这里运行数据会超时。

如何优化

不管怎样我们都需要遍历一层数组,确定nums[i],在这里我们没有办法优化。但是对于内层循环,我们应该怎样优化呢?研究异或运算的性质得到,同1同0异或为0,一1一0异或才为1。由于每个二进制数的高位权值较大,所以对于给定的nums[i],我们只需要找出nums[j],它满足在nums中他的高位尽可能和nums[i]的高位不同,这样他们高位上异或得到一,结果也就更大。

在这里由于涉及到位运算,而二进制数是由给定位串组成的。对于给定范围数字都是31位整数,可以先建一棵trie,然后对于列表每个元素不进行整个列表的遍历搜索,而是搜索这棵树。这样用trieO(N)的内层循环优化到常数级别,因为可以把遍历整个长度为N的数组的过程变为遍历一个深度为31的trie树的过程。

从根节点向下应该是高位到低位

代码如下:

/**
	trie树节点
**/
class TrieNode{
public:
    TrieNode* children[2] = {NULL, NULL};
};

/**
	trie树
**/
class Trie{
public:
    TrieNode* root = new TrieNode();
    
    /**
    	向trie中插入一个数,按从root高位->低位存储
    **/
    void insert(int num){
        TrieNode* now = root;
        
        // 倒序确保从高位到低位优先
        for(int i = 30; i >= 0; i--){
            int tmp = num >> i & 1; // 数的二进制形式第i位值
            if(now->children[tmp] == NULL){ // 如果对应位的节点不存在
                now->children[tmp] = new TrieNode();
            }
            now = now->children[tmp];
        }
    }
    
    /**
    	在trie中查找num的xor最大值
    **/
    int query(int num){
        TrieNode* now = root;
        int res = 0, tmp;
        
        for(int i = 30; i >= 0; i--){
            tmp = num >> i & 1;
            if(now->children[!tmp]){
                res += 1 << i;
                tmp = !tmp;
            }
            now = now->children[tmp];
        }
        
        return res;
    }
};

class Solution {
public:
    int findMaximumXOR(vector<int>& nums) {
        Trie trie;
        
        // 建立trie树
        for(int i = 0; i < nums.size(); i++){
            trie.insert(nums[i]);
        }
        
        // 在trie树中找出各个元素的最大匹配并更新结果
        int maxXOR = 0;
        for(int i = 0; i < nums.size(); i++){
            maxXOR = max(maxXOR, trie.query(nums[i]));
        }
        
        return maxXOR;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值