算法基礎——最大異或對

原題連接ios

在給定的N個整數A1,A2……AN中選出兩個進行xor(異或)運算,獲得的結果最大是多少?函數

輸入格式
第一行輸入一個整數N。spa

第二行輸入N個整數A1~AN。code

輸出格式
輸出一個整數表示答案。ci

數據範圍
1 ≤ N ≤ 10^5,
0 ≤ Ai < 2^31get

輸入樣例:io

3
1 2 3

輸出樣例:stream

3

解題關鍵:循環

由於異或時只有當兩個數相同二進制數位上的數字不一樣時纔會爲 11 ^ 0 = 1, 0 ^ 1 = 1, 0 ^ 0 = 0, 1 ^ 1 = 0,因此要找出最大的異或對,就須要讓兩個數的二進制數位上的數儘量不一樣便可。二進制

Q & A :

Q :這裏對於 ~i 作一下解釋,爲何 ~i 能夠等價於i >= 0
A :-1 在二進制中全是 1,因此 -1 的反碼的二進制就全是 0 了,這樣當 i-- 一直減,減到 -1 的時候就能跳出循環了。(🤪其實並無什麼卵用,就只是在關鍵時候影響一下代碼的可讀性而已)。

最後,解釋一下代碼中的Query()函數中的 res += 1 << i;的意思。此處截取Y總的解釋:若是當前子樹中,存在第 i 位和 x 的第 i 位不一樣的數,說明答案的第 i 位能夠變成 1,就把 res 的第 i 位二進制位變成 1 。

完整AC代碼:

#include <iostream>
#include <cstdio>

using namespace std;
const int N = 100010, M = 3100010;

int son[M][2], idx;

void Insert(int x){
    int p = 0;
    for(int i = 30; ~i; i--){   //~i等價於i >= 0,這裏從x二進制的第31位開始枚舉每一位上的數,因此這裏左移了30位,枚舉的是第31位上的數
        int u = x >> i & 1; //判斷x這個數的第i位上的數是1仍是0
        if(!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
}

int Query(int x){
    int p = 0, res = 0;
    for(int i = 30; ~i; i--){
        int u = x >> i & 1; //若是u == 1說明第i爲上的數爲1,若是爲0則反之。
        if(son[p][!u]){ //判斷和x這個數的第i位上不同的數的這個分支是否是存在的。
            //若是存在,說明異或出來的這個數的第i位上的數能夠爲1
            res += 1 << i;
            p = son[p][!u];
        }
        //和x這個數的第i位上不同的數的這個分支不存在
        else p = son[p][u]; //不存在就只能讓p走向存在的這個分支
    }
    return res;
}

int main(){
    int n, res = 0;
    cin >> n;

    //讀入數據
    for(int i = 0; i < n; i++){
        int x;
        cin >> x;
        Insert(x);
        res = max(res, Query(x));
    }
    cout << res << endl;
    return 0;
}
相關文章
相關標籤/搜索