给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。
找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。
你能在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,就往右子树走,走完了就记录一下这条路径上的这个数是多少。
然后再线性扫描数组,用贪心的策略向下遍历树,贪心的地方在于,如果当前位上是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