数组中两数的最大异或值

给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。

找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i,j < n。

你能在O(n)的时间解决这个问题吗?

示例:

输入: [3, 10, 5, 25, 2, 8]

输出: 28

解释: 最大的结果是 5 ^ 25 = 28.

这道题是一道典型的位操作Bit Manipulation的题目,我开始以为异或值最大的两个数一定包括数组的最大值,但是OJ给了另一个例子{10,23,20,18,28},这个数组的异或最大值是10和20异或,得到30。那么只能另辟蹊径,正确的做法是按位遍历,题目中给定了数字的返回不会超过231,那么最多只能有32位,我们用一个从左往右的mask,用来提取数字的前缀,然后将其都存入HashSet中,我们用一个变量t,用来验证当前位为1再或上之前结果res,看结果和HashSet中的前缀异或之后在不在HashSet中,这里用到了一个性质,若a^b=c,那么a=b^c,因为t是我们要验证的当前最大值,所以我们遍历HashSet中的数时,和t异或后的结果仍在HashSet中,说明两个前缀可以异或出t的值,所以我们更新res为t,继续遍历,如果上述讲解不容易理解,那么建议自己带个例子一步一步试试,并把每次循环中HashSet中所有的数字都打印出来,基本应该就能理解了,算了,还是博主带着大家来看题目中给的例子吧:

3        10        5        25        2        8

11      1010     101     11001     10      1000

我们观察这些数字最大的为25,其二进制最高位在 i=4 时为1,那么我们的循环[31, 5]之间是取不到任何数字的,所以不会对结果res有任何影响。

当 i=4 时,我们此时mask为前28位为'1'的二进制数,跟除25以外的任何数相'与',都会得到0。 然后跟25的二进制数10101相'与',得到二进制数10000,存入HashSet中,那么此时HashSet中就有0和16两个数字。此时我们的t为结果res(此时为0)'或'上二进制数10000,得到二进制数10000。然后我们遍历HashSet,由于HashSet是无序的,所以我们会取出0和16中的其中一个,如果prefix取出的是0,那么t=16'异或'上0,还等于16,而16是在HashSet中存在的,所以此时结果res更新为16,然后break掉遍历HashSet的循环。实际上prefix先取16的话也一样,那么t=16'异或'上16,等于0,而0是在HashSet中存在的,所以此时结果res更新为16,然后break掉遍历HashSet的循环。

3        10        5        25        2        8

11      1010     101     11001     10      1000

当 i=3 时,我们此时mask为前29位为'1'的二进制数,如上所示,跟数字3,5,2中任何一个相'与',都会得到0。然后跟10的二进制数1010,或跟8的二进制数1000相'与',都会得到二进制数1000,即8。跟25的二进制数11001相'与',会得到二进数11000,即24,存入HashSet中,那么此时HashSet中就有0,8,和24三个数字。此时我们的t为结果res(此时为16)'或'上二进制数1000,得到二进制数11000,即24。此时遍历HashSet中的数,当prefix取出0,那么t=24'异或'上0,还等于24,而24是在HashSet中存在的,所以此时结果res更新为24,然后break掉遍历HashSet的循环。大家可以尝试其他的数,当prefix取出24,其实也可以更新结果res为24的。但是8就不行啦,因为HashSet中没有16。不过无所谓了,我们只要有一个能更新结果res就可以了。

3        10        5        25        2        8

11      1010     101     11001     10      1000

当 i=2 时,我们此时mask为前30位为'1'的二进制数,如上所示,跟3的二进制数11相'与',会得到二进制数0,即0。然后跟10的二进制数1010相'与',会得到二进制数1000,即8。然后跟5的二进制数101相'与',会得到二进制数100,即4。然后跟25的二进制数11001相'与',会得到二进制数11000,即24。跟数字2和8相'与',分别会得到0和8,跟前面重复了。所以最终HashSet中就有0,4,8,和24这四个数字。此时我们的t为结果res(此时为24)'或'上二进制数100,得到二进制数11100,即28。那么就要验证结果res能否取到28。我们遍历HashSet,当prefix取出0,那么t=28'异或'上0,还等于28,但是HashSet中没有28,所以不行。当prefix取出4,那么t=28'异或'上二进制数100,等于24,在HashSet中存在,Bingo!结果res更新为28。其他的数可以不用试了。

3        10        5        25        2        8

11      1010     101     11001     10      1000

当 i=1 时,我们此时mask为前31位为'1'的二进制数,如上所示,每个数与mask相'与'后,我们HashSet中会有2,4,8,10,24这五个数。此时我们的t为结果res(此时为28)'或'上二进制数10,得到二进制数11110,即30。那么就要验证结果res能否取到30。我们遍历HashSet,当prefix取出2,那么t=30'异或'上2,等于28,但是HashSet中没有28,所以不行。当prefix取出4,那么t=30'异或'上4,等于26,但是HashSet中没有26,所以不行。当prefix取出8,那么t=30'异或'上8,等于22,但是HashSet中没有22,所以不行。当prefix取出10,那么t=30'异或'上10,等于20,但是HashSet中没有20,所以不行。当prefix取出24,那么t=30'异或'上24,等于6,但是HashSet中没有6,所以不行。遍历完了HashSet所有的数,结果res没有被更新,还是28。

3        10        5        25        2        8

11      1010     101     11001     10      1000

当 i=0 时,我们此时mask为前32位为'1'的二进制数,如上所示,每个数与mask相'与'后,我们HashSet中会有2,3,5,8,10,25这六个数。此时我们的t为结果res(此时为28)'或'上二进制数1,得到二进制数11101,即29。那么就要验证结果res能否取到29。取出HashSet中每一个数字来验证,跟上面的验证方法相同,这里博主偷懒就不写了,最终可以发现,结果res无法被更新,还是28,所以最终的结果就是28。

综上所述,我们来分析一下这道题的核心。我们希望用二进制来拼出结果的数,最终结果28的二进制数为11100,里面有三个'1',我们来找一下都是谁贡献了这三个'1'?在 i=4 时,数字25贡献了最高位的'1',在 i=3 时,数字25贡献了次高位的'1',在 i=2 时,数字5贡献了第三位的'1'。而一旦某个数贡献了'1',那么之后在需要贡献'1'的时候,此数就可以再继续贡献'1'。而一旦有两个数贡献了'1'后,那么之后的'1'就基本上只跟这两个数有关了,其他数字有'1'也贡献不出来。验证方法里使用了前面提到的性质,a ^ b = t,如果t是所求结果话,我们可以先假定一个t,然后验证,如果a ^ t = b成立,说明该t可以通过a和b'异或'得到。参见代码如下:

 import java.util.HashSet;

 class Solution {
public static int findMaximumXOR(int[] nums) {
int max = 0;
int mask = 0;
for (int i = 31; i >= 0; i--) {
// 从最高位试着找nums的前缀
mask = mask | (1 << i);
HashSet<Integer> set = new HashSet<Integer>();
for (int num : nums) {
set.add(mask & num);
}
//判断最大异或结果的当前位是否为1
int temp=max|(1<<i);
for (int prefix: set){
if (set.contains(prefix^temp)) {
max=temp;
}
}
}
return max;
}
}

Leetcode 421.数组中两数的最大异或值的更多相关文章

  1. LeetCode 421. 数组中两个数的最大异或值(Maximum XOR of Two Numbers in an Array) 71

    421. 数组中两个数的最大异或值 421. Maximum XOR of Two Numbers in an Array 题目描述 给定一个非空数组,数组中元素为 a0, a1, a2, - , a ...

  2. Java实现 LeetCode 421 数组中两个数的最大异或值

    421. 数组中两个数的最大异或值 给定一个非空数组,数组中元素为 a0, a1, a2, - , an-1,其中 0 ≤ ai < 231 . 找到 ai 和aj 最大的异或 (XOR) 运算 ...

  3. 421 Maximum XOR of Two Numbers in an Array 数组中两个数的最大异或值

    给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 .找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i,  j < ...

  4. [Swift]LeetCode421. 数组中两个数的最大异或值 | Maximum XOR of Two Numbers in an Array

    Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231. Find the maximum re ...

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

    题目链接:https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array/ 题目大意: 略. 分析: 字典树 + 贪心. ...

  6. 求数组中两数之和等于target的两个数的下标

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元 ...

  7. [LeetCode]1464. 数组中两元素的最大乘积

    给你一个整数数组 nums,请你选择数组的两个不同下标 i 和 j,使 (nums[i]-1)*(nums[j]-1) 取得最大值. 请你计算并返回该式的最大值. 示例 1: 输入:nums = [3 ...

  8. python实现给定一个数和数组,求数组中两数之和为给定的数

    给定一个整数数组和一个目标值,找出数组中和为目标值的两个数.你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2, 7, 11, 15], target = ...

  9. leetcode-421-数组中两个数的最大异或值*(前缀树)

    题目描述: 方法一: class Solution: def findMaximumXOR(self, nums: List[int]) -> int: root = TreeNode(-1) ...

随机推荐

  1. 22/tcp open|filtered ssh 80/tcp open|filtered http

    22/tcp open|filtered ssh80/tcp open|filtered http nmap不能确定该端口是打开还是过滤,这可能是扫描一个打开的端口,但没有回应.

  2. 对Yii 2.0模型rules的理解(load()无法正确装载数据)

    在实际开发中,遇到数据表新增字段而忘记了在对应模型中rules规则中添加新增的字段,而导致load()方法装载不到新增字段,导致新增字段无法写入数据库中.   解决办法:在新增字段后及时在对应模型ru ...

  3. SharePoint 2013 缺少站点保存为模板选项

    如果您尝试在SharePoint Server 2013中保存站点,我们没有看到“将站点另存为模板”选项,则可能是因为该站点已启用站点发布功能.如 之前文章提到 “SharePoint 2010 缺少 ...

  4. 编写生成32位大写和小写字符的md5的函数

    package nicetime.com.practise; import java.security.MessageDigest; /** * MD5加密是JAVA应用中常见的算法,请写出两个MD5 ...

  5. BZOJ 3130: [Sdoi2013]费用流 网络流+二分

    3130: [Sdoi2013]费用流 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1230  Solved: ...

  6. 10款免费的MySQL数据库图形化管理工具

    绝大多数的关系数据库都明显不同于MS Access,它们都有两个截然不同的部分:后端作为数据仓库,前端作为用于数据组件通信的用户界面.这种设计非常巧妙,它并行处理两层编程模型,将数据 层从用户界面中分 ...

  7. 得到本地应用程序的EXE的路径

    实现效果: 知识运用: Application类的ExecutablePath属性 //获取启动了应用程序的可执行文件的路径和可执行文件的名称    public static string Exec ...

  8. 2018.5.5 phpStorm破解2017.3版本方法

    方法一 注册时,在打开的License Activation窗口中选择"License server",在输入框输入下面的网址: http://im.js.cn:8888 (新) ...

  9. 跑yscacaca/HHAR-Data-Process出现的问题

    直接按照说明跑: python dataAli-sameUserDevice.py python pairDataFile.py python sep_HHAR_data.py 但在sep_HHAR_ ...

  10. E - Polycarp and Snakes

    E - Polycarp and Snakes 题意:在一个全是点的图上开始画线,每次将一行或一列任意长度染成字母,一笔染一种字母,字母必须从a开始连续到后面某个字母可以覆盖. 问所给图案是否满足 , ...