微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

LeetCode 1707. 与数组元素的最大异或

如何解决LeetCode 1707. 与数组元素的最大异或

给定一个由非负整数组成的数组 nums。您还将获得一个查询数组,其中查询 [i] = [xi,mi]。

第 i 个查询的答案是 xi 和任何不超过 mi 的 nums 元素的最大按位异或值。换句话说,对于所有 j 的答案是 max(nums[j] XOR xi) 使得 nums[j]

返回一个整数数组答案,其中 answer.length == queries.length 和 answer[i] 是第 i 个查询的答案。 这个python解决方案使用了Trie,但LeetCode仍然显示TLE?

 import operator

 class TrieNode:
      def __init__(self):
          self.left=None
          self.right=None
   
 class Solution:
     def insert(self,head,x):
         curr=head
         for i in range(31,-1,-1):
             val = (x>>i) & 1
             if val==0:
                if not curr.left:
                   curr.left=TrieNode()
                       curr=curr.left
                   else:
                       curr=curr.left
               else:
                   if not curr.right:
                       curr.right=TrieNode()
                       curr=curr.right
                   else:
                       curr=curr.right
       
           
       def maximizeXor(self,nums: List[int],queries: List[List[int]]) -> List[int]:
           res=[-10]*len(queries)
           nums.sort()
           for i in range(len(queries)):
               queries[i].append(i)
           queries.sort(key=operator.itemgetter(1))
           head=TrieNode()
          
           for li in queries:
               max=0
               xi,mi,index=li[0],li[1],li[2]
               m=2**31
               node = head
               pos=0
               if mi<nums[0]:
                   res[index]=-1
                   continue
               for i in range(pos,len(nums)):
                   if mi<nums[i]:
                       pos=i
                       break
                   self.insert(node,nums[i])
               node=head
               for i in range(31,-1):
                   val=(xi>>i)&1
                   if val==0:
                       if node.right:
                           max+=m
                           node=node.right
                       else:
                           node=node.left
                   else:
                       if node.left:
                           max+=m
                           node=node.left
                       else:
                           node=node.right
                   m>>=1
               res[index]=max
           return -1

解决方法

这里有替代的 Trie 实现来解决这个问题:

[注:1) max(x XOR y for y in A); 2)对MSB位进行贪婪; 3) 对查询进行排序]

class Trie:
    def __init__(self):
        self.root = {}
    
    def add(self,n):
        p = self.root
        for bitpos in range(31,-1,-1):
            bit = (n >> bitpos) & 1
            if bit not in p:
                p[bit] = {}
            p = p[bit]
    
    def query(self,n):
        p = self.root
        ret = 0
        if not p:
            return -1
        for bitpos in range(31,-1):
            bit = (n >> bitpos) & 1
            inverse = 1 - bit
            if inverse in p:
                p = p[inverse]
                ret |= (1 << bitpos)
            else:
                p = p[bit]
                
        return ret

class Solution:
    def maximizeXor(self,nums: List[int],queries: List[List[int]]) -> List[int]:
        
        n = len(nums)
        trie = Trie()
        q = sorted(enumerate(queries),key = lambda x: x[1][1])
        nums.sort()
        res = [-1] * len(queries)
        i = 0
        for index,(x,m) in q:
            while i < n and nums[i] <= m:
                trie.add(nums[i])
                i += 1
            res[index] = trie.query(x)
        return res
,

问题在于您正在为每个查询构建一个新的 Trie。更糟糕的是,使用线性搜索找到 <= mi 中的最大值 nums。只需使用

max((n for n in nums if n <= mi),key=lambda n: n^xi,default=-1) 

这里的解决方案是从一开始就构建 trie,然后使用该 trie 简单地过滤小于 mi 的值:

import math
import bisect

def dump(t,indent=''):
    if t is not None:
        print(indent,"bit=",t.bit,"val=",t.val,"lower=",t.lower)
        dump(t.left,indent + '\tl')
        dump(t.right,indent + '\tr')

class Trie:
    def __init__(self,bit,val,lower):
        self.bit = bit
        self.val = val
        self.lower = lower
        self.left = None
        self.right = None
        
    def solve(self,mi,xi):
        print('-------------------------------------------')
        print(self.bit,"mi(b)=",(mi >> self.bit) & 1,"xi(b)=",(xi >> self.bit) & 1,"mi=","xi=",xi)
        dump(self)
        
        if self.val is not None:
            # reached a leave of the trie => found matching value
            print("Leaf")
            return self.val
        
        if mi & (1 << self.bit) == 0:
            # the maximum has a zero-bit at this position => all values in the right subtree are > mi
            print("Left forced by max")
            return -1 if self.left is None else self.left.solve(mi,xi)
        
        # pick based on xor-value if possible
        if (xi >> self.bit) & 1 == 0 and self.right is not None and (mi > self.right.lower or mi == ~0):
            print("Right preferred by xi")
            return self.right.solve(mi,xi)
        elif (xi >> self.bit) & 1 == 1 and self.left is not None:
            print("Left preferred by xi")
            return self.left.solve(~0,xi)
        
        # pick whichever is available
        if self.right is not None and (mi > self.right.lower or mi == ~0):
            print("Only right available")
            return self.right.solve(mi,xi)
        elif self.left is not None:
            print("Only left available")
            return self.left.solve(~0,xi)
        else:
            print("None available")
            return -1
        
        
def build_trie(nums):
    nums.sort()
        
    # msb of max(nums)
    max_bit = int(math.log(nums[-1],2))  # I'll just assume that nums is never empty
    print(max_bit)
        
    def node(start,end,template):
        print(start,template,nums[start:end])
        
        if end - start == 1:
            # reached a leaf
            return Trie(0,nums[start],nums[start])
        elif start == end:
            # a partition without values => no Trie-node
            return None
            
        # find pivot for partitioning based on bit-value of specified position (bit)
        part = bisect.bisect_left(nums,template | (1 << bit),start,end)
        print(part)
            
        # build nodes for paritioning       
        res = Trie(bit,None,nums[start])
        res.left = node(start,part,bit - 1,template)
        res.right = node(part,template | (1 << bit))
        return res
        
    return node(0,len(nums),max_bit,0)

class Solution:
    def maximizeXor(self,queries: List[List[int]]) -> List[int]:
        trie = build_trie(nums)
        return [trie.solve(mi if mi <= nums[-1] else ~0,xi) for xi,mi in queries]

我有点懒惰,只是使用 ~0 表示可以忽略最大值,因为子树中的所有值都小于 mi。基本思想是 ~0 & x == x 对任何整数 x 都成立。不像 @DanielHao's answer 那样简单,但能够处理查询流。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。