zoukankan      html  css  js  c++  java
  • [LeetCode] 421. Maximum XOR of Two Numbers in an Array

    Given an integer array nums, return the maximum result of nums[i] XOR nums[j], where 0 ≤ i ≤ j < n.

    Follow up: Could you do this in O(n) runtime?

    Example 1:

    Input: nums = [3,10,5,25,2,8]
    Output: 28
    Explanation: The maximum result is 5 XOR 25 = 28.

    Example 2:

    Input: nums = [0]
    Output: 0
    

    Example 3:

    Input: nums = [2,4]
    Output: 6
    

    Example 4:

    Input: nums = [8,10,2]
    Output: 10
    

    Example 5:

    Input: nums = [14,70,53,83,49,91,36,80,92,51,66,70]
    Output: 127 

    Constraints:

    • 1 <= nums.length <= 2 * 104
    • 0 <= nums[i] <= 231 - 1

    数组中两个数的最大异或值。题意是给一个数组,请输出其中两个数字异或的最大值。

    我这里提供一个位运算的做法,大部分内容参考了这个帖子。首先复习一下异或XOR的运算规则:两个二进制的数字,同一个位置上的数字不同,XOR为1;数字相同的时候,XOR为0。所以这里如果要找XOR最大的结果,最好能找到两个数字,他们的二进制表达最好在每一位上都不同。而且XOR是具有交换律的,如果你有a ^ b = c,你同时可以得到a ^ c = b和b ^ c = a。假如a和b是来自于nums的数字的话,我们为了要使c最大,我们可以试图去找一个前缀很大的数字a和一个前缀很小的数字b,这样他们做XOR运算的时候才有可能使c的前缀更大。

    这里我们创建一个mask去判断每个二进制数字的前缀。mask是由10000...000到11111...111(32位)。随着mask的变大,比如从10000到11111(我这里暂时用5位表示),如果nums里面的数字跟mask比较的时候,他们的前缀里面也包含1的话,在做AND运算的时候,会得到这些前缀。此时我们在找前缀的同时,把这些前缀存到一个hashset里。每一个mask都会与input数组里面的每一个数字做AND运算,得到一个前缀,set里最终留下的是所有unique的前缀。

    此时再创建一个mask叫做temp,也是从1 - 31逐渐增加1的个数。这里我理解temp就是在猜最后XOR的结果,然后往回套,看hashset是否存在两个数字a和b满足a ^ b = temp。判断的方式是对于hashset里面的某个元素a,如果满足a ^ temp = b,同时b也在hashset中,则表明找到了一个有效的temp。

    时间O(n)

    空间O(n)

    Java实现

     1 class Solution {
     2     // 先确定高位,再确定低位(有点贪心算法的意思),才能保证这道题的最大性质
     3     // 一位接着一位去确定这个数位的大小
     4     // 利用性质: a ^ b = c ,则 a ^ c = b,且 b ^ c = a
     5     public int findMaximumXOR(int[] nums) {
     6         int res = 0;
     7         int mask = 0;
     8         for (int i = 31; i >= 0; i--) {
     9             // 注意点1:注意保留前缀的方法,mask 是这样得来的
    10             // 用异或也是可以的 mask = mask ^ (1 << i);
    11             mask = mask | (1 << i);
    12             // System.out.println("mask is " + Integer.toBinaryString(mask));
    13             Set<Integer> set = new HashSet<>();
    14             for (int num : nums) {
    15                 // 注意点2:这里使用 & ,保留前缀的意思(从高位到低位)
    16                 set.add(num & mask);
    17             }
    18 
    19             // 这里先假定第 n 位为 1 ,前 n-1 位 res 为之前迭代求得
    20             int temp = res | (1 << i);
    21             System.out.println("temp is " + Integer.toBinaryString(temp));
    22             for (Integer prefix : set) {
    23                 if (set.contains(prefix ^ temp)) {
    24                     res = temp;
    25                     break;
    26                 }
    27             }
    28         }
    29         return res;
    30     }
    31 }

    LeetCode 题目总结

  • 相关阅读:
    [LeetCode] 1898. Maximum Number of Removable Characters
    [LeetCode] 1897. Redistribute Characters to Make All Strings Equal
    [LeetCode] 1400. Construct K Palindrome Strings
    235. 二叉搜索树的最近公共祖先
    349. 两个数组的交集
    海量数据TOPK 问题
    121. 买卖股票的最佳时机
    删除数组中为0元素
    这行字符串中出现频率最高的字符
    50. Pow(x, n)
  • 原文地址:https://www.cnblogs.com/cnoodle/p/13684568.html
Copyright © 2011-2022 走看看