LeetCode-Python-421. 数组中两个数的最大异或值

给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。

找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i,  j < 

你能在O(n)的时间解决这个问题吗?

示例:

输入: [3, 10, 5, 25, 2, 8]

输出: 28

解释: 最大的结果是 5 ^ 25 = 28.

思路:

思路分析:这种题就不要暴力法,指名道姓说要O(n)。根据提示需要使用建树。
首先我们需要知道,二进制高位为1会大于低位的所有和,比如"11111111"最高位代表的"1"按权展开为128,
而后面的“1111111”按权展开的和也只是127。所以进行异或时应该尽量选择高位异或结果为“1”的。
第一步:遍历数组,我们按照二进制[31,30,…,1, 0]各位的状态进行建树,left放置0,right放置1。
比如某个int型数的二进制是"0110110…",我们需要将其放置到[left,right,right,left,right,right,left…]。
第二步:遍历数组,按照贪心策略,尽量维持当前选择的方向能保证当前能位异或结果为1。
--------------------- 
作者:hestyle 
来源:CSDN 
原文:https://blog.csdn.net/qq_41855420/article/details/88756998 
版权声明:本文为博主原创文章,转载请附上博文链接!

自己想是想不出来O(n)的,学习了一波才弄懂。

主要思路就是把nums里的每个数建树,一共有31位,如果当前位上是0,就往左子树走,如果当前位是1,就往右子树走,走完了就记录一下这条路径上的这个数是多少。

扫描二维码关注公众号,回复: 5788908 查看本文章

然后再线性扫描数组,用贪心的策略向下遍历树,贪心的地方在于,如果当前位上是0,而有右子树,就往右子树走,因为这样0和右子树上的1异或可以得到1,反之就往左子树走。

这种贪心策略的正确性在于,优先保障高位异或得到1,而对于二进制的数来说,为了得到更大的异或值,最高位的1的重要性比其他位1更高,比如 1000一定大于0111,所以得到的一定会是最大的异或值。

class Solution(object):
    def findMaximumXOR(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        #贪心+trierTree
        root = TreeNode(-1)
        
        for num in nums:
            cur_node = root #当前的node
            
            for i in range(0, 32):               #代表32个位
                # print num, 1 <<(31 - i), num & (1 <<(31 - i))
                if num & (1 <<(31 - i)) == 0:    #如果当前位与运算的结果是1, 就往左走
                    if not cur_node.left:
                        cur_node.left = TreeNode(0)
                    cur_node = cur_node.left
                else:                            #如果当前位与运算的结果是0, 就往右走
                    if not cur_node.right:
                        cur_node.right = TreeNode(1)
                    cur_node = cur_node.right
            cur_node.left = TreeNode(num)        #在最后的左叶子节点记录一下这个数的值
                    
        res = 0
        for num in nums:
            cur_node = root
            
            for i in range(0, 32):
                # print cur_node.val, cur_node.left, cur_node.right
                if num & (1 <<(31 - i)) == 0:     #与运算结果为0,如果能往右走,就往右走,因为右子树代表1,这样在这一位上异或会得到1
                    if cur_node.right:           #能往右走
                        cur_node = cur_node.right#就往右走
                    else:                        #不能往右走
                        cur_node = cur_node.left#就往左走
                else:                            #与运算结果为1,如果能往左走,就往左走,因为左子树代表0,这样异或会得到1
                    if cur_node.left:            #能往左走
                        cur_node = cur_node.left#就往左走
                    else:                        #不能往左走
                        cur_node = cur_node.right#就往右走  
            temp = cur_node.left.val             #得到这条路径存放的数的值
                
            res = max(res, num ^ temp)           #每次刷新res为最大值
                
        return res

猜你喜欢

转载自blog.csdn.net/qq_32424059/article/details/89003303