【哈希集合】【位运算-异或和】【数组】【2023-11-04】
421. 数组中两个数的最大异或值
找出数组中两个数的最大异或结果。
一看数据量达到了 1 0 5 10^5 105,那时间复杂度为 O ( n 2 ) O(n^2) O(n2) 的方法必定超时,因此需要去找 O ( n l o g n ) O(nlogn) O(nlogn) 或者 O ( n ) O(n) O(n) 时间复杂度的方法。
对于本题,最直白的想法是枚举数组中的两个数,计算异或值,找出最大值返回即可,但是该方法的需要两次枚举数,属于嵌套循环,时间复杂度为 O ( n 2 ) O(n^2) O(n2),一定超时,故需要考虑其他方法。
接下来将介绍两种方法来解决本题:
以下思路与代码主要参考 【图解】简洁高效,一图秒懂!(Python/Java/C++/Go/JS/Rust)。
为了得到最大的异或和数,简称为 结果
,我们希望 结果
的二进制数从高位到低位尽可能出现更多的 1
。为什么对二进制数进行判断?因为,位运算都是二进制位之间的运算(异或和、按位与等等),我们对二进制数进行判断会更加接近底层运算(异或和、按位与等等)。
跳出从数组中直接找数的固化思维,根据 结果
的特征,我们从最高位到最低位来找数。最高位也就是数组中最大数的二进制数长度减一,我们从该位开始枚举 i
:
newAns = res | (1 << i)
,也就是从数组中找到两个数(低于 i
的比特位为 0
)满足这两个数的异或和等于 newAns
,如果有,则更新 res = newAns
,否则 res
不变;b
,由于 b ⊕ b = 0 b\oplus b = 0 b⊕b=0,所以得到 a = n e w A n s ⊕ b a = newAns \oplus b a=newAns⊕b。这样就可以一边枚举 b
,一边在哈希表中查找 n e w A n s ⊕ b newAns \oplus b newAns⊕b 了。实现代码
class Solution {
public:
int findMaximumXOR(vector<int>& nums) {
int mx = *max_element(nums.begin(), nums.end());
int high_bit = mx ? 31 - __builtin_clz(mx) : -1;
int res = 0, mask = 0;
unordered_set<int> seen;
for (int i = high_bit; i >= 0; --i) {
seen.clear();
mask |= (1 << i);
int new_ans = res | (1 << i);
for (int x : nums) {
x &= mask;
if (seen.contains(new_ans ^ x)) {
res = new_ans;
break;
}
seen.insert(x);
}
}
return res;
}
};
复杂度分析
时间复杂度: O ( n l o g U ) O(nlogU) O(nlogU), n n n 是数组 nums
的长度, U U U 是数组中最大元素的位数。
空间复杂度: O ( n ) O(n) O(n),哈希表中至多存放 n
个数。
class Solution:
def findMaximumXOR(self, nums: List[int]) -> int:
ans = mask = 0
high_bit = max(nums).bit_length() - 1
for i in range(high_bit, -1, -1): # 从最高位开始枚举
mask |= 1 << i
new_ans = ans | (1 << i) # 这个比特位可以是 1 吗?
seen = set()
for x in nums:
x &= mask # 低于 i 的比特位置为 0
if new_ans ^ x in seen:
ans = new_ans # 这个比特位可以是 1
break
seen.add(x)
return ans
如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 。
如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。
最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 哦。