演算法之字首樹——最大異或和

it_was發表於2020-10-06

難度中等:smirk:

給定一個非空陣列,陣列中元素為 a0, a1, a2, … , an-1,其中 0 ≤ ai < 2^31

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

你能在O(n)的時間解決這個問題嗎?

示例:
輸入: [3, 10, 5, 25, 2, 8]
輸出: 28
解釋: 最大的結果是 5 ^ 25 = 28.

暴力法雖然簡單,但是。。。都能想到,而且複雜度很高

異或就是對應bit位上如果相同,那麼兩者運算結果為0,不同則為 1,即:

  • 1 ^ 1 = 0 ^ 0 = 0
  • 0 ^ 1 = 1 ^ 0 = 1

即要想異或出來的數字大,那麼應該儘量保持兩位是不同的!,這樣對應位異或出來為1,結果才會比較大!
那麼什麼時候最大呢?

儘量使高位異或出 1 才越能保持最大!!!:boom: :boom: :boom:

為什麼呢?因為有 1 * * * * 一定大於 0 * * * * 性質

就是不管低位情況如何,只要高位為 1,一定比高位不是 1 的要大, 所以在遍歷過程中,只需要尋找與當前位不同的 ,使其異或結果為 1 即可!如若沒有則並無影響。

這個過程中,可以使用字首樹來儲存每一個數字的各位情況!
儘量尋找高位上不同於當前位的結點則體現貪心
演算法之字首樹——最大異或和

實現方法: 字首樹 + 貪心

package ddx.December.day6;

public class Normal_421 {
    public int maxXOR(int[] nums) {
        BitTrieNode root = buildBitTrie(nums);
        return searchMaXOR(nums,root);
    }
    //字首樹 + 貪心!
    public int searchMaXOR(int[] nums, BitTrieNode root){
        int max = -1; //記錄最大值
        for(int num : nums){//遍歷陣列,找到每個數字與哪個數字異或結果最大!
            BitTrieNode curNode = root;
            for(int index = 31;index >= 0;index--){
                int curBit = num & (1 << index); //拿到數字最高位
                if(curBit == 0){ //如果最高位是0 ,那麼我需要字首樹中對應位為 1 的
                    curNode = curNode.one != null ? curNode.one:curNode.zero; //儘量尋找 與當前bit位相反的結點!!!!!
                }else{ //反之亦然
                    curNode = curNode.zero != null ? curNode.zero:curNode.one; //儘量尋找 與當前bit位相反的結點!!!!!
                }
            }
            max = Math.max(max,num ^ curNode.val); //更新最大值!此時curode.val就是與 num異或最大的數字!!!
        }
        return max;
    }

    public BitTrieNode buildBitTrie(int[] nums) { //建立位元位字首樹
        BitTrieNode root = new BitTrieNode(-1); //初始化根節點
        for (int num : nums) {
            BitTrieNode curNode = root;
            for (int index = 31; index >= 0; index--) { //每個數最多不超過32位!將這32位全部建立完
                int curBit = num & (1 << index); //拿到當前位
                if (curBit == 0) {
                    if (curNode.zero == null) { //若沒有則建立
                        curNode.zero = new BitTrieNode(0);
                    }
                    curNode = curNode.zero;
                } else {
                    if (curNode.one == null) {//若沒有則建立
                        curNode.one = new BitTrieNode(1);
                    }
                    curNode = curNode.one;
                }
            }
            curNode.val = num; //賦值
        }
        return root;
    }

}

class BitTrieNode {
    public BitTrieNode zero;
    public BitTrieNode one;
    public int val;

    BitTrieNode(int val) {
        this.val = val;
    }
}

輸出結果

3異或結果最大的數為:25   異或結果為 :2610異或結果最大的數為:25   異或結果為 :195異或結果最大的數為:25   異或結果為 :2825異或結果最大的數為:5   異或結果為 :282異或結果最大的數為:25   異或結果為 :278異或結果最大的數為:25   異或結果為 :17
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章