ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

leetcode 421.数组中两个数的最大异或值 - 字典树 + 贪心

2021-05-16 19:58:23  阅读:137  来源: 互联网

标签:node nums int res trie 异或 421 leetcode nextDigit


leetcode 421.数组中两个数的最大异或值 - 字典树 + 贪心

题干

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

示例 1:
输入:nums = [3,10,5,25,2,8]
输出:28
解释:最大运算结果是 5 XOR 25 = 28.

示例 2:
输入:nums = [0]
输出:0

示例 3:
输入:nums = [2,4]
输出:6

示例 4:
输入:nums = [8,10,2]
输出:10

示例 5:
输入:nums = [14,70,53,83,49,91,36,80,92,51,66,70]
输出:127

提示:
1 <= nums.length <= 2 * 104
0 <= nums[i] <= 231 - 1

知识点&算法

因为异或的时候需要逐位比较,而数字的二进制表示可能长短不一,所以将他们统一储存为31位二进制数(因为数据范围是0 - 2 ^ 31 - 1)。
然后枚举数,和其他的数进行异或运算,取最大异或值。
用字典树对已有的数据进行维护。
对于当前枚举的数,从高位开始,贪心地尽可能选取相反的位值,如果字典树中已有的数无法满足取相反位,就取相同位。

题解

class Solution {
public:
    struct trie{
        struct trie* nextDigit[2];
        trie(){
            memset(nextDigit,0,sizeof(nextDigit));
        }
    };
    int shiftLimit = 30;
    trie* root = new trie;
    trie* node;

    void insert(int num){
        node = root;
        for(int i = shiftLimit ; i >= 0 ; --i){
            int digit = (num >> i) & 1;
            if(node->nextDigit[digit] == nullptr) node->nextDigit[digit] = new trie;
            node = node->nextDigit[digit];
        }
        return;
    }

    int search(int num){
        node = root;
        int res = 0;
        for(int i = shiftLimit ; i >= 0 ; --i){
            int digit = (num >> i) & 1;
            if(digit == 0){
                if(node->nextDigit[1]){
                    res = res * 2 + 1;
                    node = node->nextDigit[1];
                }else{
                    res *= 2;
                    node = node->nextDigit[0];
                }
            }else{
                if(node->nextDigit[0]){
                    res = res * 2 + 1;
                    node = node->nextDigit[0];
                }else{
                    res *= 2;
                    node = node->nextDigit[1];
                }
            }
        }
        return res;
    }

    int findMaximumXOR(vector<int>& nums) {
        int n = nums.size(),ans = 0;
        for(int i = 0 ; i < n ; ++i) insert(nums[i]);
        for(int i = 0 ; i < n ; ++i) ans = max(ans,search(nums[i]));
        return ans;
    }
};

最后主函数更新答案的部分可以只写一个循环,只匹配枚举的数和此前的数,枚举的数和此后的数相当于枚举到此后的数与之前的数,所以不会遗漏。
i = 1 ; i < n 相比 i = 0 ; i < n - 1可以节省每次循环一个运算的时间开销

for(int i = 1 ; i < n ; ++i){
	insert(nums[i-1]);
	ans = max(ans,search(nums[i]));
}

标签:node,nums,int,res,trie,异或,421,leetcode,nextDigit
来源: https://blog.csdn.net/weixin_43662405/article/details/116902011

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有