二叉搜索树的最近公共祖先

标签: 深度优先搜索 二叉搜索树 二叉树

难度: Easy

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

示例 1:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和节点 8 的最近公共祖先是 6。

示例 2:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

说明:

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉搜索树中。

注意:本题与主站 235 题相同:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

Submission

运行时间: 88 ms

内存: 18.8 MB

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        while root:
            if q.val > root.val and p.val > root.val:
                root = root.right
            elif q.val < root.val and p.val < root.val:
                root = root.left
            else:
                break
        return root

Explain

本题解利用了二叉搜索树的性质来找到两个节点的最近公共祖先。在二叉搜索树中,对于任何一个节点,其左子树的所有节点值都小于该节点值,其右子树的所有节点值都大于该节点值。算法从根节点开始,比较两个节点值p和q与当前节点值的大小关系:如果p和q的值都大于当前节点值,则说明它们的公共祖先在当前节点的右侧子树中;如果p和q的值都小于当前节点值,则说明它们的公共祖先在当前节点的左侧子树中;如果p和q的值一个大于当前节点值,一个小于或等于当前节点值,那么当前节点就是它们的最近公共祖先。

时间复杂度: O(h),其中h是树的高度。对于平衡的二叉搜索树,h约为log(n)。

空间复杂度: O(1),因为算法仅使用有限的几个变量,而不依赖于输入大小。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        while root:
            # 如果p和q都大于root的值,说明公共祖先在右子树
            if q.val > root.val and p.val > root.val:
                root = root.right
            # 如果p和q都小于root的值,说明公共祖先在左子树
            elif q.val < root.val and p.val < root.val:
                root = root.left
            # 如果p和q分布在root两侧,或者其中之一就是root,那么root就是最近公共祖先
            else:
                break
        return root

Explore

在这种情况下,节点root将直接被确定为最近公共祖先。这是因为根据二叉搜索树的性质,如果p等于root,而q大于或小于root,意味着q位于root的左侧或右侧子树中。这表明root是连接p和q的最直接的节点,因此root是它们的最近公共祖先。

如果p或q之一是另一个的祖先,则不需要继续查找。在这种情况下,更高层级的节点(即祖先节点)将直接作为最近公共祖先。例如,如果p是q的祖先(或反之),则p(或q)就是它们的最近公共祖先,因为从树的结构中可以看出,所有到达q的路径都必须经过p。

二叉搜索树(BST)的主要特性是每个节点的左子树只包含小于当前节点的值,每个节点的右子树只包含大于当前节点的值。这个性质使得在查找最近公共祖先时可以有效地通过比较大小来决定搜索方向,从而避免了不必要的节点访问。这种性质确保了算法不需要遍历整棵树,而是通过分而治之的方式,快速定位到最近公共祖先,大大提高了算法的效率。