【两个数的最大异或值】LeetCode421.数组中两个数的最大异或值 && LeetCode2935.找出强数对的最大异或值Ⅱ

一、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;
    }
};

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值