LeetCode421. Maximum XOR of Two Numbers in an Array


  這道題的題目很好理解,就是給你一個非空數組,求出數組中任意兩個數異或后能得到的最大值。原題鏈接:LeetCode421 。根據題目下面的tag的提示,本題的解題思路是Trie樹的利用和整數的位操作。

  這里Trie樹建立的思路是,整數在存儲時是一個占據32bit的數,因此可以看成一個含32個字符的字符串,這個字符串中的每個字符只可能是0或1。因此,將一個整數插入Trie樹就是從它的最高位開始,根據每一位上的值進入不同的分支,直到最低位。接下來,是如何找到最大的異或值,兩個數異或得到一個數,這個數的值要盡量大,那么這個數的二進制表示法中,第一個1出現的位數越高這個數就越大,即置1位越高數越大。所以,對於數組中的每一個數,要找到它和數組中其他數異或后得到的最大異或值,可以采用類似貪心的策略,從最高位開始,找和它在這一位相反的數。如果有,那么和這個數異或就得到最大異或值,如果沒有就依次往下一位找,直到找到相異的位。一開始,我采用先將數組中所有的數建成一棵Trie樹后再對每一個數求各自的最大異或值,然后再取最大值,建立Trie樹的時間復雜度是O(32n),這里的32即Trie樹的鍵值最大長度;Trie樹的高度為32,因此查找每個數的最大異或值得時間復雜度是O(32n),合起來是O(64n),提交時出現了TLE,顯然時間復雜度太高了。代碼大致如下:

 1 public class LeetCode421 {
 2 
 3     class Trie {
 4         Trie[] next;
 5 
 6         public Trie() {
 7             next = new Trie[2];
 8         }
 9     }
10 
11     public int findMaximumXOR(int[] nums) {
12         if (nums.length <= 1 || nums == null)
13             return 0;
14         Trie root = new Trie();
15         for (int num : nums) {
16             Trie node = root;
17             for (int i = 30; i >= 0; i--) {
18                 int cur = (num >>> i) & 1;
19                 if (node.next[cur] == null) {
20                     node.next[cur] = new Trie();
21                 }
22                 node = node.next[cur];
23             }
24         }
25 
26         int result = 0;
27         for (int num : nums) {
28             Trie node = root;
29             int xor = 0;
30             for (int i = 30; i >= 0; i--) {
31                 int cur = (num >>> i) & 1;
32                 //cur = cur ^ 1;
33                 if (node.next[cur ^ 1] != null) {
34                     xor += (1 << i);
35                     node = node.next[cur ^ 1];
36                 } else {
37                     node = node.next[cur];
38                 }
39             }
40             result = result > xor ? result : xor;
41         }
42         return result;
43     }
44 }
View Code

 

  其實在這個算法中,顯然有很多重復計算的部分,假設ai的最大異或值是 ai xor aj,那么aj的最大值肯定也是 aj xor ai,這里就是重復計算。因此,我決定改成在建立Trie樹的同時,對於正在插入的數,在已插入的數中查找能得到的最大異或值,即邊建Trie邊查找最大值,這樣做也能得到正確的最大異或值。代碼如下:

public class LeetCode421 {

    class Trie {
        Trie[] next;

        public Trie() {
            next = new Trie[2];
        }
    }

    public int findMaximumXOR(int[] nums) {
        if (nums.length <= 1 || nums == null)
            return 0;
        Trie root = new Trie();
        int result = 0;
        for (int num : nums) {
            int xor = 0;
            Trie insert = root, search = root;
            for (int i = 30; i >= 0; i--) {
                int bit = (num >>> i) & 1;
                int rbit = bit ^ 1;
                if (insert.next[bit] == null) {
                    insert.next[bit] = new Trie();
                }
                insert = insert.next[bit];
                if (search != null) {
                    if (search.next[rbit] != null) {
                        xor += (1 << i);
                        search = search.next[rbit];
                    } else {
                        search = search.next[bit];
                    }
                }
            }
            result = Math.max(result, xor);
        }
        return result;
    }
}

  這個算法在提交時偶爾會出現TLE的情況,有時是Accepted,應該是這個算法的時間復雜度還不夠低。看了Discuss還有很多不采用Trie的解法,並且時間復雜度都很低,看來這題Trie樹也許不是最佳解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM