📅  最后修改于: 2023-12-03 14:49:01.134000             🧑  作者: Mango
给定一棵二叉树,每个节点包含一个整数值,从根节点到叶节点沿着二进制表示的路径形成一个二进制数。求这些二进制数的按位与的最大值。
我们可以用深度优先搜索来递归遍历整棵二叉树,并计算每个从根节点到叶节点的路径的按位与的值,并找到最大值。
代码如下:
class Solution:
def maxAnd(self, root: TreeNode) -> int:
def dfs(node, total):
if not node:
return 0
total &= node.val
if not node.left and not node.right:
return total
return max(dfs(node.left, total), dfs(node.right, total))
return dfs(root, float('inf'))
时间复杂度为 $O(n)$,其中 $n$ 是二叉树中节点的个数。因为我们需要遍历整棵二叉树。
我们可以先不用遍历整棵二叉树,而是直接用位运算来计算出答案。
我们假设最终的答案是 $ans$,则二叉树中的每个节点都会对 $ans$ 的二进制位进行影响。如果第 $i$ 位上的所有值都为 1,才能让 $ans$ 在该位上为 1。
具体做法有两种,一种是从高位到低位,一位一位地确定答案;另一种是从低位到高位,一次性确定整个答案。
下面我们以第一种方法为例来讲解。
对于二叉树中的每个节点,我们可以计算出其左子树和右子树中的所有二进制数在第 $i$ 位上出现的次数 $c_l$ 和 $c_r$,这两个数加起来就是第 $i$ 位上所有数出现的次数 $c$。
如果 $c$ 不为 $2^n$,其中 $n$ 为整数,那么第 $i$ 位上的值一定为 0。
如果 $c$ 为 $2^n$,则第 $i$ 位上的值可能为 0 或 1,取决于左右子树中的二进制数在该位上是否相同。如果相同,就让第 $i$ 位上的值为 1;否则,第 $i$ 位上的值为 0。
代码如下:
class Solution:
def maxAnd(self, root: TreeNode) -> int:
ans = 0
for i in range(31, -1, -1):
cl = cr = clv = crv = 0
stack = [(root, 1 << i)]
while stack:
node, mask = stack.pop()
if not node:
continue
if mask & node.val:
clv += mask
cl += 1
if clv == crv and cl == cr:
ans += mask
if not node.left and not node.right:
crv += mask
cr += 1
stack.append((node.left, mask >> 1))
stack.append((node.right, mask >> 1))
if cl == cr == 2 ** (i + 1):
ans += min(clv, crv)
return ans
时间复杂度为 $O(n)$,其中 $n$ 是二叉树中节点的个数。因为我们需要遍历整棵二叉树。
我们也可以使用 Trie 树来计算答案。对于每个数,在 Trie 树上从高位到低位进行遍历,如果一个节点的两个子节点均存在,则必定会出现从根节点到该节点的路径上经过某一层次的两个路径,它们的按位与的值不同。
我们可以递归遍历 Trie 树来计算出所有按位与的值,从而得到最大值。
代码如下:
class Node:
def __init__(self):
self.children = {}
self.is_terminal = False
class Trie:
def __init__(self):
self.root = Node()
def insert(self, val):
node = self.root
for bit in format(val, '032b'):
if bit not in node.children:
node.children[bit] = Node()
node = node.children[bit]
node.is_terminal = True
def dfs(self, node):
if not node:
return (0, 0)
lval, lcnt = self.dfs(node.children.get('0'))
rval, rcnt = self.dfs(node.children.get('1'))
if node.is_terminal:
if lcnt == rcnt:
return (lval | rval, lcnt + 1)
else:
return (0, 0)
else:
cnt = lcnt if rval == 0 else rcnt if lval == 0 else 0
return ((lval & rval) << 1 | lval | rval, cnt)
class Solution:
def maxAnd(self, root: TreeNode) -> int:
trie = Trie()
for node in list(dfs(root)):
trie.insert(node)
return trie.dfs(trie.root)[0]
def dfs(node):
if not node:
return
yield node.val
yield from dfs(node.left)
yield from dfs(node.right)
时间复杂度为 $O(n)$,其中 $n$ 是二叉树中节点的个数。因为我们需要遍历整棵二叉树并构建 Trie 树。