1. 程式人生 > >Leetcode421. 找出陣列中兩個元素異或的最大值

Leetcode421. 找出陣列中兩個元素異或的最大值

Leetcode421. Maximum XOR of Two Numbers in an Array

題目

Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 2^31.
Find the maximum result of ai XOR aj, where 0 ≤ i, j < n.
Could you do this in O(n) runtime?

Example:
Input: [3, 10, 5, 25, 2, 8]
Output: 28
Explanation: The maximum result is 5 ^ 25 = 28.

解題分析

題目的要求很簡單,就是讓我們找出陣列中兩個元素異或的最大值,並且要求我們實現的演算法的時間複雜度為O(n)。按照常理,我們會對陣列中所有元素對進行異或然後進行比較,這樣的話時間複雜度就為O(n^2),很顯然不符合題目的要求,那麼我們就只能另闢蹊徑了。
我們可以這樣想,異或的基本原理就是將兩個數字分別轉成32位二進位制後,進行逐位比較,如果同個位置上的數字不同,則該位為1,否則為0。根據這個原理,我們從左高位進行計算,用一個掩碼mask來作為底,其中mask當前位i到左高位的所有位置上的數字為1,其它位置為0,即11…10…0。將陣列中的每個元素分別與mask進行與運算,將與運算的結果存進集合set中。
假設至少存在兩個數在當前位i上的數字不同,則可有假設:當前異或的最大值temp為max|2^i,那麼怎樣驗證當前位i上至少存在兩個數不同呢?我們可以藉助前面求得的temp值,將集合中的每個元素與temp進行異或,如果在集合中能找到一個數等於另一個數與temp異或的結果,那就說明假設成立,將temp賦值給異或最大值max。
為什麼呢這樣假設就成立了呢?我們可以這樣看,我們知道,在當前位i,mask上的數字為1,其低位全部為0。由於集合set存放的元素是陣列元素與mask進行與運算的結果,因此如果當前位i上至少有兩個數不同,那麼進行與運算後的結果當前位i就必然有0和1兩種情況,而低位的數字都相同、均為0。而我們知道,1^1=0,0^1=1,由於低位都相同,所以根據異或的結果就可以知道在當前位i上是否有兩個數字滿足要求了。
這樣當32位數字遍歷完後,最後得到的max值就是最後的答案。

原始碼

class Solution {
public:
    int findMaximumXOR(vector<int>& nums) {
        int max = 0, mask = 0;
        for (int i = 31; i >= 0; i--) {
            set<int> set;
            mask = mask | (1 << i);
            for (int num : nums) {
                set.insert(num & mask);
            }
            int
temp = max | (1 << i); for (int element : set) { if (set.find(element ^ temp) != set.end()) { max = temp; break; } } } return max; } };

以上是我對這道問題的一些想法,有問題還請在評論區討論留言~