给你一个整数数组 nums ,返回 nums[i] XOR nums[j] 的最大运算结果,其中 0 ≤ i ≤ j < n 。
进阶:你可以在 O(n) 的时间解决这个问题吗?
示例 1:
输入:nums = [3,10,5,25,2,8]
输出:28
解释:最大运算结果是 5 XOR 25 = 28.
这道题比较有意思,用到前缀树与贪心思想将复杂度降到O(n)
1.构建二进制前缀树
具体来说就是利用数的二进制表示,从高位到低位构建一棵树(因为只有0和1 两个值,所以是一棵二叉树),每个从根节点到叶子节点的路径都表示一个数。(构建的树看下图)
2.搜索前缀树
然后遍历数组中的数字,将每一个二进制位,在对应的层中找到一个异或的最大值,也就是:如果是1,找0的那条路径,如果是0,找1的那条路径。
这样搜索下来的路径就是这个数字和整个数组异或的最大值
具体步骤是:
对于2, 二进制从高到低是 0,0,1,0
第一步:二进制位是0,我们到第四层去选择,有1,我们选择1这个节点,异或计算结果是1
第二步:二进制位是0,在第三层,上一步选择的节点没有为1的子节点,所以我们只能选择0,异或计算结果是0
第三步:二进制位是1,在第二层,上一步选择的节点的子节点下有0的节点,我们选择0,异或计算结果是1
第四部:二进制位是0,在第一层,上一步选择的节点的子节点下只有一个0,所以选择0,异或计算结果是0
所以我们异或的结果是1010, 十进制表示是10.
class Trie:
def __init__(self, val):
self.val = val
self.child = {}
class Solution:
def findMaximumXOR(self, nums: List[int]) -> int:
#取得最大长度
L = len(format(max(nums), 'b'))-1
# 构建前缀树
root = Trie(-1)
for n in nums:
curr = root
for i in range(L, -1, -1):
v = (n >> i) & 1
if v not in curr.child:
curr.child[v] = Trie(v)
print(curr.val)
curr = curr.child[v]
#show
# queue = collections.deque()
# queue.append(root)
# res1 = []
# while queue:
# size = len(queue)
# level = []
# for _ in range(size):
# cur = queue.popleft()
# if not cur:
# continue
# level.append(cur.val)
# for i in [0, 1]:
# if i in cur.child:
# queue.append(cur.child[i])
# if level:
# res1.append(level)
# print(res1)
res = 0
#搜索
for n in nums:
curr = root
total = 0
for i in range(L, -1, -1):
v = (n >> i) & 1
if 1-v in curr.child:
total = total * 2 + 1
curr = curr.child[1-v]
else:
total = total * 2
curr = curr.child[v]
#print(n, total)
res = max(res, total)
return res
首先,我们先构造前缀树,因为二进制只存在0,1,所以用{}字典结构存放子节点。将num按位存放到前缀树中。构造完前缀树后,我们可以用中序遍历查看树的结构。然后,我们对nums中的每个数进行搜索,寻找对应最大异或值。搜索过程:将n的每一位二进制数在前缀树的对应层中找到数字相异的child,然后沿着child路径继续向下寻找下一位,即利用贪心在前缀树路径中剪枝。