技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTALG

Lowest Common Ancestor of a Binary Search Tree

所属馆藏
Algorithm
文件格式
Markdown
原始路径
Algorithm/1-10_Lowest Common Ancestor of a Binary Search Tree_二叉搜索树的最近公共祖先
本文目录9 个章节
  1. 题目 / Problem
  2. 示例 / Examples
  3. 约束 / Constraints
  4. 解题思路:利用 BST 的有序性质 / Approach: Use the BST Ordering Property
  5. 执行过程 / Walkthrough
  6. 复杂度 / Complexity
  7. 递归解法 / Recursive Approach
  8. 与普通二叉树解法的区别 / Difference from a General Binary Tree
  9. 易错点 / Common Pitfalls

Lowest Common Ancestor of a Binary Search Tree(二叉搜索树的最近公共祖先)

题目 / Problem

中文: 给定一棵二叉搜索树(BST),请找出树中两个指定节点 pq 的最近公共祖先(LCA)。

最近公共祖先是同时拥有 pq 作为后代的最深节点,其中允许一个节点成为它自己的后代。换句话说,如果 pq 的祖先,那么 p 也可以是它们的最近公共祖先。
The lowest common ancestor is the deepest node that has both p and q as descendants, and a node is allowed to be a descendant of itself.

English: Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST.

示例 / Examples

以下三个示例使用的二叉搜索树结构:
The following binary search tree is used in the examples:

          6
        /   \
       2     8
      / \   / \
     0   4 7   9
        / \
       3   5

Example 1

二叉搜索树:节点 2 和 8 的最近公共祖先 / BST: LCA of nodes 2 and 8

Input:  root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6

解释 / Explanation:
节点 2 和节点 8 分别位于节点 6 的两侧,因此最近公共祖先是 6。
Nodes 2 and 8 lie on opposite sides of node 6, so their LCA is 6.

Example 2

二叉搜索树:节点 2 和 4 的最近公共祖先 / BST: LCA of nodes 2 and 4

Input:  root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
Output: 2

解释 / Explanation:
节点 2 是节点 4 的祖先。由于节点可以是自己的后代,因此最近公共祖先是 2。
Node 2 is an ancestor of node 4. Because a node can be a descendant of itself, their LCA is 2.

Example 3

Input:  root = [2,1], p = 2, q = 1
Output: 2

约束 / Constraints

  • 树中的节点数在 [2, 10⁵] 范围内。
    The number of nodes in the tree is in the range [2, 10⁵].
  • -10⁹ <= Node.val <= 10⁹
  • 所有节点的值互不相同。
    All Node.val values are unique.
  • p != q
  • pq 一定存在于这棵二叉搜索树中。
    Both p and q exist in the BST.

解题思路:利用 BST 的有序性质 / Approach: Use the BST Ordering Property

二叉搜索树中的每个节点都满足:
Every node in a binary search tree satisfies:

  • 左子树中的所有值都小于当前节点的值。
    Every value in the left subtree is smaller than the current node's value.
  • 右子树中的所有值都大于当前节点的值。
    Every value in the right subtree is greater than the current node's value.

从根节点开始,设当前节点为 current
Starting at the root, let the current node be current:

  1. 如果 p.valq.val 都小于 current.val,说明两个节点都在左子树中,继续向左搜索。
    If both p.val and q.val are smaller than current.val, both nodes are in the left subtree, so continue left.
  2. 如果 p.valq.val 都大于 current.val,说明两个节点都在右子树中,继续向右搜索。
    If both values are greater than current.val, both nodes are in the right subtree, so continue right.
  3. 否则,两个节点位于当前节点的两侧,或者当前节点就是 pq。此时 current 就是最近公共祖先。
    Otherwise, the nodes lie on opposite sides, or current is itself p or q. In either case, current is the LCA.

这个“分叉点”是从根节点向下搜索时遇到的第一个同时覆盖 pq 的节点,因此它就是最深的公共祖先。
This split point is the first node encountered from the root that contains both p and q in its subtree, so it is their lowest common ancestor.

JavaScript 实现 / JavaScript Implementation

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *   this.val = val;
 *   this.left = this.right = null;
 * }
 */

/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
function lowestCommonAncestor(root, p, q) {
  let current = root;

  while (current !== null) {
    if (p.val < current.val && q.val < current.val) {
      current = current.left;
    } else if (p.val > current.val && q.val > current.val) {
      current = current.right;
    } else {
      return current;
    }
  }

  return null;
}

题目保证 pq 都存在于树中,因此按照约束一定会在循环中找到最近公共祖先。末尾的 return null 只是函数的兜底返回值。
The problem guarantees that both nodes exist in the tree, so the LCA will be found inside the loop. The final return null is only a fallback.

执行过程 / Walkthrough

Example 1:p = 2q = 8

当前节点 / current比较 / Comparison操作 / Action
62 < 6 < 8两个节点在两侧,返回 6 / Nodes split; return 6

Example 2:p = 2q = 4

当前节点 / current比较 / Comparison操作 / Action
62 < 64 < 6两者都在左侧,移动到 2 / Both are left; move to 2
2current === p当前节点就是公共祖先,返回 2 / Current node is the LCA; return 2

current 等于 p 时,两个值不可能同时严格小于或严格大于 current.val,所以会进入 else 并正确返回 p
When current equals p, both values cannot be strictly smaller or strictly greater than current.val, so execution reaches else and correctly returns p.

复杂度 / Complexity

设二叉搜索树的高度为 h
Let the height of the binary search tree be h.

  • 时间复杂度:O(h),每次只沿树的一条路径向下移动。
    Time: O(h), because the algorithm follows only one path down the tree.
    • 平衡二叉搜索树中为 O(log n)
      It is O(log n) in a balanced BST.
    • 树退化为链表时,最坏为 O(n)
      It is O(n) in the worst case when the tree is skewed.
  • 空间复杂度:O(1),迭代解法只使用一个额外指针。
    Space: O(1), because the iterative solution uses only one extra pointer.

递归解法 / Recursive Approach

同样的判断逻辑也可以递归实现:
The same decision process can be implemented recursively:

function lowestCommonAncestorRecursive(root, p, q) {
  if (p.val < root.val && q.val < root.val) {
    return lowestCommonAncestorRecursive(root.left, p, q);
  }

  if (p.val > root.val && q.val > root.val) {
    return lowestCommonAncestorRecursive(root.right, p, q);
  }

  return root;
}
  • 时间复杂度 / Time: O(h)
  • 空间复杂度 / Space: O(h),递归调用栈的深度取决于树高。
    The recursion stack depth depends on the height of the tree.

由于节点数最多达到 10⁵,极度倾斜的树可能使递归调用栈过深,因此迭代解法更加稳妥。
Because the tree may contain up to 10⁵ nodes, a highly skewed tree can make the recursion stack too deep, so the iterative solution is safer.

与普通二叉树解法的区别 / Difference from a General Binary Tree

普通二叉树没有“左小右大”的性质,通常需要分别搜索左右子树,时间复杂度为 O(n)
A general binary tree lacks the ordered left-smaller/right-greater property, so both subtrees usually need to be searched, resulting in O(n) time.

本题是二叉搜索树,可以根据节点值直接排除一整棵子树,将搜索限制在一条路径上。
Because this problem uses a BST, node values let us eliminate an entire subtree and restrict the search to a single path.

易错点 / Common Pitfalls

  • 不要忽略二叉搜索树的有序性质,否则会写成普通二叉树的 O(n) 解法。
    Use the BST ordering property instead of defaulting to the general O(n) binary-tree solution.
  • 最近公共祖先可以是 pq 本身。
    The LCA may be p or q itself.
  • 只有当两个节点都严格小于或都严格大于当前节点时,才能继续向同一侧移动。
    Move to one side only when both nodes are strictly smaller or both are strictly greater than the current node.
  • 返回的是节点对象,不是节点的值。
    Return the node object, not its value.
  • 不需要假设 p.val < q.val;当前判断对两种顺序都适用。
    Do not assume p.val < q.val; the comparisons work in either order.
457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS