這道題的題目很好理解,就是給你一個非空數組,求出數組中任意兩個數異或后能得到的最大值。原題鏈接: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 }
其實在這個算法中,顯然有很多重復計算的部分,假設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樹也許不是最佳解。