本文正在参加「Java主题月 – Java 刷题打卡」,详情查看 活动链接
题目描述
给你一个整数数组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 * 10^4
0 <= nums[i] <= 2^31 - 1
题目分析
根据题目中的说明,x
的个数是有限的,它的值是从0到2^31 – 1,那我可不可以指定x
从2^31 - 1
递减到0
,判断存不存在nums[i] XOR nums[j] = x
。这么做是可以的,而且x不需要从2^31 - 1
开始递减,而是从nums
中最大一个就可以了,但是这样遍历次数太多了,太暴力了,就不这样做了。
要想获得最大的x
,就要从最高位开始看,尽量保证高位为1
,那么是不是可以不像上边那样直接指定x
的值,而是从高位开始确定x
的值,一次确定一位,直到最后得到x
的值。
- 比如我先假设
x
的最高位为1
,那么是不是说只要nums
中存在两个数,他们的最高位异或为1
就可以了; - 如果成立,我再假设
x
的次高位为1
,那么就是nums
中存在两个数它们的前两位异或的值为11
,如果不存在这样的两个数呢?那就说明x
的次高位一定是0
,x
最前边两位就是10
,这里假设不存在这样的两个数,所以x
前两位就是10
- 同样的,假设
x
第三位是1
,判断nums
中是否存在两个数前三位异或的值是101
,如果存在,就确定x
前三位是101
,否则就是100
- 就这样一直判断到最后一位就可以了
public class Solution {
public int findMaximumXOR(int[] nums) {
int x = 0;
//set存放nums中每个元素从第30位到第i位的二进制
// 每次确定一位
for (int i = 30; i >= 0; i--) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
// num是31位,如果右移30得到的就是最高位
set.add(num >> i);
}
x = x << 1;
// x先左移一位再加一,就是假设x的第i位为1
int tempX = x + 1;
for (Integer num : set) {
if (set.contains(tempX ^ num)) {
// 如果找到了说明x的第i位是1,把tempX赋给x
//否则就是x只左移,没有加1,就是x的第i位为0
x = tempX;
break;
}
}
}
return x;
}
public static void main(String[] args) {
int[] nums = {3, 10, 5, 25, 2, 8};
System.out.println(new Solution().findMaximumXOR(nums));
}
}
复制代码
总结
代码中要注意的地方
num >> i
,表示把num
右移i
位,num >> 1
相当于num / 2
,如果一个十进制5
,5 / 2 = 5 >> 1 = (101 >> 1)2 = (10)2,就是把二进制101
右移一位变成10
x << 1
,表示x
左移一位,二进制101
左移一位变成1010
- “tempX ^ num
,表示异或,相同值异或结果为
0,不同值异或为
1`
外层循环是常数,内存循环遍历nums
,所以时间复杂度是O(n)
,用了一个HashSet
,所以空间复杂度是O(n)
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END