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

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

难度简单151

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

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

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

img

示例 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 为不同节点且均存在于给定的二叉搜索树中。

在明白原理之后,可以删除代码注释,可读性会更高

方法一:迭代

这道题的主要目的就是希望我们返回一个节点(该节点的值大于 p p p q q q中的一个,并且小于 p p p q q q 中的一个),如此以来做起来就十分简单。只需要在root!=NULL 的情况下迭代,当 p , q p,q p,q v a l val val都小于 r o o t − > v a l root->val root>val时, r o o t = r o o t − > l e f t root=root->left root=root>left.当 p , q p,q p,q都大于 r o o t − > v a l root->val root>val时, r o o t = r o o t − > r i g h t root=root->right root=root>right,否则,返回 r o o t root root。这里包含两种情况:

  • 第一: r o o t − > v a l = = p − v a l root->val==p-val root>val==pval或者 r o o t − > v a l = = q − > v a l root->val==q->val root>val==q>val
  • 第二: r o o t − > v a l root->val root>val大于其中一个,小于另一个。
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
    //循环终止条件,这里也可以写为while(true) ,因为在遍历到叶子节点时,一定可以找到合适的出口

    while (root != NULL)             
    {
        //p和q的值都大于当前节点的值,证明p和q在当前节点的右侧
        if (q->val > root->val && p->val > root->val)

            //遍历右子树
            root = root->right;
        
        //p和q的值都小于当前节点的值,证明p和q在当前节点的左侧
        else if (q->val < root->val && p->val < root->val)
            //遍历左子树
            root = root->left;
        else
            //两种递归出口
            return root;
    }
    return NULL;
}
剑指 Offer 68 - II. 二叉树的最近公共祖先

img

此题目与剑指Offer 68 - I 的区别是二叉树不再是二叉搜索树

方法一:递归/先序遍历二叉树

方法的思想就是:在二叉树的根节点左右两边【如上图在根节点3的左右两边】遍历二叉树,搜索 p − > v a l 或 q − > v a l p->val或q->val p>valq>val 。(我们在遍历的过程中,只要遇到相等的节点,直接返回,不必继续查找另外一个节点)这样就会出现以下三种情况:

  1. 在左子树(节点3的左边子树)中找到了 p − > v a l 或 者 q − > v a l p->val或者q->val p>valq>val ,在右子树(节点3的右边子树)中也找到了 p − > v a l 或 者 q − > v a l p->val或者q->val p>valq>val 的其中一个。那么 p 和 q p和q pq 的最近公共祖先只能是 r o o t root root
  2. 在左子树中找到了 p − > v a l 或 者 q − > v a l p->val或者q->val p>valq>val ,但在右子树中没有找到,那么就说明两个节点都在左子树中,并且最先找到的节点就是 p 和 q p和q pq 的最近公共祖先。
  3. 这一情况同第二种情况,在右子树中找到了找到了 p − > v a l 或 者 q − > v a l p->val或者q->val p>valq>val ,但是在左子树中没有找到 p 和 q p和q pq 中的任何一个,显然, p 和 q p和q pq 同时存在于root的右子树中,那么最先找到的这个节点就是 p 和 q p和q pq 的最近公共祖先。

问题:为什么没有第四种情况,在左子树和右子树中都没有找到?

因为在题目的说明 处写道:“p、q 为不同节点且均存在于给定的二叉树中” 所以无论如何都不会 出现在在左右子树中都没找到的情况。

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
{
    
    //root==NULL 表明没找到,返回root(也就是NULL) 
    //root->val==p->val||root->val==q->val ,表明找到了p或q其中的一个节点,返回这个节点
    
    if (root == NULL || root->val == p->val || root->val == q->val)
        return root;


    // 在左子树中寻找的结果
    TreeNode* left = lowestCommonAncestor(root->left, p, q);


    //在右子树中寻找的结果
    TreeNode* right = lowestCommonAncestor(root->right, p, q);


    //对寻找结果分类讨论


    if (left == NULL&&right!=NULL)      //左子树中找到,右子树中没找到
        return right;
    if (left != NULL && right == NULL)  //左子树中没找到,右子树中找到
        return left;
    if (left && right)                  //左右子树中都找到
        return root;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值