这道题的题目很好理解,就是给你一个非空数组,求出数组中任意两个数异或后能得到的最大值。原题链接: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树也许不是最佳解。