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一秒鐘。留個言點個讚唄,謝謝你#

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章