【每日一题】数组中两个数的最大异或值

文章目录

  • Tag
  • 题目来源
  • 题目解读
  • 解题思路
    • 方法一:哈希集合
  • 其他语言
    • python3
  • 写在最后

Tag

【哈希集合】【位运算-异或和】【数组】【2023-11-04】


题目来源

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

【每日一题】数组中两个数的最大异或值_第1张图片

题目解读

找出数组中两个数的最大异或结果。


解题思路

一看数据量达到了 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 不变;
  • 判断两个数的异或和的解题思想是 两数之和 哈希表解法。把代码中的减法改成异或就行,这是因为如果 a ⊕ b = n e w A n s a\oplus b = newAns ab=newAns,那么两边同时异或 b,由于 b ⊕ b = 0 b\oplus b = 0 bb=0,所以得到 a = n e w A n s ⊕ b a = newAns \oplus b a=newAnsb。这样就可以一边枚举 b,一边在哈希表中查找 n e w A n s ⊕ b newAns \oplus b newAnsb 了。

实现代码

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 个数。


其他语言

python3

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

写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 哦。

你可能感兴趣的:(LeetCode每日一题,哈希集合,位运算-异或,数组,2023-11-04)