一、LeetCode421.数组中两个数的最大异或值
https://leetcode.cn/problems/maximum-xor-of-two-numbers-in-an-array/
描述:
给你一个整数数组 nums
,返回 nums[i] XOR nums[j]
的最大运算结果,其中 0 ≤ i ≤ j < n
。
示例 1:
输入:nums = [3,10,5,25,2,8] 输出:28 解释:最大运算结果是 5 XOR 25 = 28.
示例 2:
输入:nums = [14,70,53,83,49,91,36,80,92,51,66,70] 输出:127
提示:
1 <= nums.length <= 2 * 105
0 <= nums[i] <= 231 - 1
思路:
每次都从最高位开始判断,判断当前位是否能取到1。
具体来说,每次都取当前位以及它的高位,低位暂时不考虑,假设当前位为1,那么连同它已经判断过的位置所组成的数为x_next,那么如果该位可以取到1,那么就应该能找到num1,使得x_next ^ (num2 >> k) == (num1 >> k)否则该位就不能取到1,当前结果-1。
具体代码如下:
class Solution {
public:
int findMaximumXOR(vector<int>& nums) {
int x = 0;
// 从第30位开始枚举
for(int k = 30; k >= 0; k--){
unordered_set<int> s;
// 将所有的pre^k(a_j)放入哈希表中
// 这里指的是将num的高k位放入哈希表中
for(int num : nums){
// 只保留从最高位开始到第k个二进制位为止的部分
s.insert(num >> k);
}
// 目前x包括从最高位开始到第k+1个二进制位为止的部分
int x_next = 2 * x + 1;
bool found = false;
for(int num : nums){
if(s.count(x_next ^ (num >> k))){
found = true;
break;
}
}
if(found){
x = x_next;
}else{
x = x_next - 1;
}
}
return x;
}
};
二、LeetCode2935.找出强数对的最大异或值Ⅱ
https://leetcode.cn/problems/maximum-strong-pair-xor-ii/description/
描述:
给你一个下标从 0 开始的整数数组 nums
。如果一对整数 x
和 y
满足以下条件,则称其为 强数对 :
|x - y| <= min(x, y)
你需要从 nums
中选出两个整数,且满足:这两个整数可以形成一个强数对,并且它们的按位异或(XOR
)值是在该数组所有强数对中的 最大值 。
返回数组 nums
所有可能的强数对中的 最大 异或值。
注意,你可以选择同一个整数两次来形成一个强数对。
示例 1:
输入:nums = [1,2,3,4,5]
输出:7
解释:数组 nums
中有 11 个强数对:(1, 1), (1, 2), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (3, 5), (4, 4), (4, 5) 和 (5, 5) 。
这些强数对中的最大异或值是 3 XOR 4 = 7 。
示例 2:
输入:nums = [10,100]
输出:0
解释:数组 nums
中有 2 个强数对:(10, 10) 和 (100, 100) 。
这些强数对中的最大异或值是 10 XOR 10 = 0 ,数对 (100, 100) 的异或值也是 100 XOR 100 = 0 。
示例 3:
输入:nums = [500,520,2500,3000]
输出:1020
解释:数组 nums
中有 6 个强数对:(500, 500), (500, 520), (520, 520), (2500, 2500), (2500, 3000) 和 (3000, 3000) 。
这些强数对中的最大异或值是 500 XOR 520 = 1020 ;另一个异或值非零的数对是 (5, 6) ,其异或值是 2500 XOR 3000 = 636 。
提示:
1 <= nums.length <= 5 * 104
1 <= nums[i] <= 220 - 1
思路:仔细分析,这道题其实也就是求两个数的最大异或值,只不过对两个数的大小关系有一定的限制,不妨设x <= y,那么|x - y| <= min(x, y),即y - x <= x,即2 * x >= y。
由于本题数组的顺序并不会影响结果,所以很容易想到也许可以排个序,并且,题目的要求其实也是针对大小关系的限制,那么如果我们从大到小排序,就可以达到,当遍历到一个数字的时候,判断当前位能否取1,就需要往回看之前有没有数字可以和自己异或之后当前位取1,并且这个数字(不比当前数字大)的大小的2倍需要不小于当前数字,因此在LeetCode421的基础上,我们不仅需要对数组从大到小排序,还需要同时存放当前第k位连同之前的高位所对应的原始数字,也就是原来算法中的set变成了map,但是整体的思路是大致相同的。
具体代码如下:
class Solution {
public:
int maximumStrongPairXor(vector<int>& nums) {
// 大的在后面被枚举到
sort(nums.begin(), nums.end());
int x = 0;
// 从第19位开始枚举
for(int k = 19; k >= 0; k--){
unordered_map<int, int> mp;
int x_next = 2 * x + 1;
bool found = false;
// 将所有的pre^k(a_j)放入哈希表中
// 目前x包括从最高位开始到第k+1个二进制位为止的部分
for(int num : nums){
// 只保留从最高位开始到第k个二进制位为止的部分
if(mp.count(x_next ^ (num >> k)) &&
(mp[x_next ^ (num >> k)] * 2 >= num)){
found = true;
break;
}
mp[num >> k] = num;
}
if(found){
x = x_next;
}else{
x = x_next - 1;
}
}
return x;
}
};