LeetCode(421):数组中两个数的最大异或值 Maximum XOR of Two Numbers in an Array(Java)

2019.11.20 LeetCode 从零单刷个人笔记整理(持续更新)

github:https://github.com/ChopinXBP/LeetCode-Babel

如果想用o(n)的方法找到最大的异或值,根本思路是将n^2的遍历计算转换成32n的按位匹配。这题可以用两种方法:

1.异或性质+贪心算法

异或的性质:如果 a ^ b = c 成立,那么a ^ c = b 与 b ^ c = a 均成立。

从最高位开始遍历按位确定result的可能值。模板mask从最高位至第i位为全1,用于截取前缀。

用mask将数组中所有数的前缀放入哈希表中,在result高位确定的基础上假设第i位为1,若哈希表中存在prifix1使得prefix2 = prefix1 ^ value,说明存在value = prefix1 ^ prefix2,更新result。

2.前缀树

根据数组元素构造一棵二叉前缀树,结点值存在代表当前位上存在该数值。

利用trie对每一个数num找最大异或值curMax。从最高位开始深度遍历,bit代表树上该位的值(0/1),trie遍历倾向于向相反值(bit1)走,若(bit1)存在则curMax该位更新为1;反之向1走,curMax该位更新为0。


传送门:数组中两个数的最大异或值

Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231.

Find the maximum result of ai XOR aj, where 0 ≤ i, j < n.

Could you do this in O(n) runtime?

给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。

找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。

你能在O(n)的时间解决这个问题吗?

示例:

输入: [3, 10, 5, 25, 2, 8]

输出: 28

解释: 最大的结果是 5 ^ 25 = 28.


import java.util.HashSet;

/**
 *
 * Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231.
 * Find the maximum result of ai XOR aj, where 0 ≤ i, j < n.
 * 给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。
 * 找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i,j < n 。
 *
 */

public class MaximumXOROfTwoNumbersInAnArray {
    //异或性质+贪心算法
    //异或的性质:如果 a ^ b = c 成立,那么a ^ c = b 与 b ^ c = a 均成立。
    public int findMaximumXOR(int[] nums) {
        int result = 0;
        int mask = 0;
        //从最高位开始按位确定result的可能值
        for(int i = 31; i >= 0; i--){
            //mask从最高位至第i位为全1,用于截取前缀,将数组中所有数的前缀放入哈希表中
            mask |= (1 << i);
            HashSet<Integer> set = new HashSet<>();
            for(int num : nums){
                set.add(num & mask);
            }
            //在result高位确定的基础上假设第i位为1
            int temp = result | (1 << i);
            for(Integer prefix : set){
                //若哈希表中存在prifix1使得prefix2 = prefix1 ^ value,说明存在value = prefix1 ^ prefix2
                if(set.contains(prefix ^ temp)){
                    result = temp;
                    break;
                }
            }
        }
        return result;
    }

    //前缀树
    public int findMaximumXOR2(int[] nums) {
        if(nums == null || nums.length == 0){
            return 0;
        }
        Trie trie = new Trie();
        return trie.getMaxXORValue(nums);
    }

    private class TrieNode{
        TrieNode[] children = new TrieNode[2];
    }

    private class Trie{
        TrieNode root;
        Trie(){
            root = new TrieNode();
        }

        public void insert(int num){
            TrieNode curNode = root;
            for(int i = 31; i >= 0; i--){
                int bit = (num >>> i) & 1;
                if(curNode.children[bit] == null){
                    curNode.children[bit] = new TrieNode();
                }
                curNode = curNode.children[bit];
            }
        }

        public int getMaxXORValue(int[] nums){
            //根据数组元素构造一棵二叉前缀树,结点值存在代表当前位上存在该数值
            for(int num : nums){
                insert(num);
            }
            int max = Integer.MIN_VALUE;
            //利用trie对每一个数num找最大异或值curMax
            for(int num : nums){
                TrieNode curNode = root;
                int curMax = 0;
                //bit代表树上该位的值(0/1),trie遍历倾向于向相反值(bit^1)走,若(bit^1)存在则curMax该位更新为1;反之向1走,curMax该位更新为0
                for(int i = 31; i >= 0; i--){
                    int bit = (num >>> i) & 1;
                    if(curNode.children[bit ^ 1] != null){
                        curMax |= (1 << i);
                        curNode = curNode.children[bit ^ 1];
                    }else {
                        curNode = curNode.children[bit];
                    }
                }
                max = curMax > max ? curMax : max;
            }
            return max;
        }
    }
}




#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#

发布了246 篇原创文章 · 获赞 316 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_20304723/article/details/103172142