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树也许不是最佳解。

posted @ 2017-02-15 20:33  栗子拉面酱  阅读(1690)  评论(0编辑  收藏  举报