1. 程式人生 > WINDOWS開發 >AcWing 143. 最大異或對

AcWing 143. 最大異或對

AcWing 143.最大異或對

題目描述

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

輸入格式

第一行輸入一個整數N。

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

輸出格式

輸出一個整數表示答案。

資料範圍

1≤N≤10^5,
0≤Ai<2^31

輸入樣例:

3
1 2 3

輸出樣例:

3

思路

先想一下暴力的做法,然後優化

int arr[N];
int ans = 0;
for(int i = 0; i < n; ++i){
      for(int j = 0; j < i; ++j)
           ans = (ans,arr[i] ^ arr[j]);
}

顯然上述的暴力方式時間複雜度為O(n ^ 2),明顯會超時,這樣就要想著如何優化,這裡我們可以優化內層迴圈:採用trie樹來優化
我們每次把每一個數的二進位制的沒一個位儲存到trie樹中,這樣每一個葉子節點就是代表了一個數
每輸入一個x,先插入樹中,我們從最高位開始與樹中的資料匹配,如果存在與x在同一位置二進位制位相反的數那麼就選擇樹中的這樣的點(就相當於把已經插入的數分成了兩個集合...),如果不存在就選自己。如下所示
技術分享圖片

程式碼實現

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;
int s[N * 32][2],ans = 0,idx = 0;

void insert(int x){
    int p = 0;
    for(int i = 30; i>=0; --i){
        int ch = x >> i & 1;
        if(s[p][ch] == 0) s[p][ch] = ++ idx;
        p = s[p][ch];
    }
}

int search(int x){//當前的數和已經插入的樹中的數,找異或最大值
    int p = 0,ans = 0;
    for(int i = 30; i >= 0; --i){
        int ch = x >> i & 1;
        if(s[p][!ch]){
            p = s[p][!ch];
            ans = ans * 2 + !ch;
        }
        else{
            p = s[p][ch];
            ans = ans * 2 + ch;
        }
    }
    return ans;
}
int main(){
    int n;cin >> n;
    while(n --){
        int x; cin >>x;
        insert(x);
        ans = max(ans,x ^ search(x));
    }
    cout << ans << endl;
    return 0;
}