SWE / AI Engineer · VO Coding

Microsoft LCA:BST 分叉点到普通二叉树节点身份追问

BST 用值域寻找两目标分叉处;推广到普通树时改为后序汇总目标出现数,并验证节点确实存在。

题目重点:BST 用值域寻找两目标分叉处;推广到普通树时改为后序汇总目标出现数,并验证节点确实存在。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • BST 训练版值互异且两个目标值都存在;普通二叉树版接收两个 Node 对象,按身份而非数值判断,可处理值重复。
  • 若普通树中任一目标缺失,返回 None;a 和 b 同一个对象且存在时返回该对象。
  • 树无共享子节点/环;代码递归版对极深树可改显式后序栈。

解题路线

  1. BST:令 low=min(a,b)、high=max(a,b)。当前节点值若比 low 小,两目标都在右;若比 high 大,都在左;否则两目标分居或某一目标就是当前节点,它是 LCA。
  2. 普通树不能依靠数值大小。后序访问左右子树,返回候选节点及找到的目标数;两个目标在两侧或当前节点就是其中一个时,当前节点成为 LCA。
  3. 继续确保 found=2 才返回候选,可防一个目标缺失时误把唯一找到的节点当 LCA。若左右子树已找到完整答案可提前返回。
  4. 正确性来自普通树 LCA 是最深且包含两个目标的子树根;BST 分叉点则是首个把两个目标同时留在当前子树、却不能都下沉到同一儿子的节点。

手动走一遍

BST 根 6,目标 2 和 8 在根两边,LCA=6;目标 2 与其子孙 4,沿左路到 2 就停止,LCA=2。普通树若目标值都等于 5,也不能用值比较辨别,必须用两个具体 Node 身份。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

"""LCA by value in a BST and by identity in a general binary tree."""

from dataclasses import dataclass


@dataclass(eq=False)
class Node:
    value: int
    left: "Node | None" = None
    right: "Node | None" = None


def bst_lca(root: Node | None, a: int, b: int) -> Node | None:
    """Assumes both distinct values exist in the BST; duplicates are not supported."""
    low, high = min(a, b), max(a, b)
    current = root
    while current is not None:
        if high < current.value:
            current = current.left
        elif low > current.value:
            current = current.right
        else:
            return current
    return None


def binary_tree_lca(root: Node | None, a: Node, b: Node) -> Node | None:
    """Return None if either node is absent; compare node identity, not values."""
    def visit(node):
        if node is None:
            return None, 0
        left_node, left_found = visit(node.left)
        if left_found == 2:
            return left_node, 2
        right_node, right_found = visit(node.right)
        if right_found == 2:
            return right_node, 2
        own = int(node is a) + int(node is b)
        found = left_found + right_found + own
        if found >= 2:
            return node, 2
        return (left_node or right_node or (node if own else None)), found

    candidate, found = visit(root)
    return candidate if found == 2 else None

复杂度

BST 时间 O(h)、迭代额外空间 O(1),h 为树高;一般树必须最坏访问 O(n) 节点,递归栈 O(h)。缺失目标检查已包含一般树遍历。

易错点与追问

容易失分的边界

  • 把 BST 的数值分叉规则直接用于普通二叉树。
  • 一般树只找到一个目标时也返回该节点。
  • 重复值树里只按 value 判断目标,识别错节点。
  • 默认 BST 平衡而把最坏复杂度写成 O(log n)。

继续深挖

  • 普通树有 parent 指针时怎样通过祖先集合求 LCA?
  • 同一棵树大量 LCA 查询如何预处理?
  • 树极深使递归栈溢出时怎样改写?
✓已复制微信号!