剑指Offer:[第19天 搜索与回溯算法(中等)]--->Ⅰ. 二叉搜索树的最近公共祖先


一、题目描述

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:对于有根树 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 为不同节点且均存在于给定的二叉搜索树中。


二、思路分析

注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献

思路

祖先的定义: 若节点 p p p 在节点 r o o t root root 的左(右)子树中,或 p = r o o t p = root p=root,则称 r o o t root root p p p 的祖先
在这里插入图片描述
最近公共祖先的定义: 设节点 r o o t root root 为节点 p p p q q q 的某公共祖先,若其左子节点 r o o t . l e f t root.left root.left 和右子节点 r o o t . r i g h t root.right root.right 都不是 p p p q q q 的公共祖先,则称 r o o t root root 是最近的公共祖先。
根据以上定义,若 r o o t root root p p p q q q 的最近公共祖先,则只可能为以下情况之一:
p p p q q q r o o t root root 的子树中,且分列 r o o t root root 的异侧(即分别在左、右子树中)
p = r o o t p = root p=root,且 q q q r o o t root root 的左或右子树中
q = r o o t q = root q=root,且 p p p r o o t root root 的左或右子树中
在这里插入图片描述
本题给定了两个重要条件:①树为二叉搜索树②树的所有节点的值都是唯一的。根据以上条件,可方便地判断 p p p q q q r o o t root root 的子树关系,即:
r o o t . v a l < p . v a l root.val < p.val root.val<p.val,则 p p p r o o t root root 右子树中
r o o t . v a l > p . v a l root.val > p.val root.val>p.val,则 p p p r o o t root root 左子树中
r o o t . v a l = p . v a l root.val = p.val root.val=p.val,则 p p p r o o t root root 指向同一节点


方法一:迭代

算法流程:
①循环搜索: 当节点root为空时跳出;
----当pq都在root的右子树中,则遍历至root.right
----否则,当pq都在root的左子树中,则遍历至root.left
----否则,说明找到了最近公共祖先,跳出
②返回值:最近公共祖先root
案例分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复杂度分析:
时间复杂度 O ( N ) \rm{O(N)} O(N):其中N为二叉树节点数,每循环一轮排除一层,二叉搜索树的层数最小为logN(满二叉树),最大为 N(退化为链表)
空间复杂度 O ( 1 ) \rm{O(1)} O(1):使用常数大小的额外空间

方法二:递归

算法流程:
①递推工作:
----当pq都在root的右子树中,则开启递归root.right并返回
----否则,当pq都在root的左子树中,则开启递归root.left并返回
②返回值:最近公共祖先root
复杂度分析:
时间复杂度 O ( N ) \rm{O(N)} O(N):其中N为二叉树节点数,每循环一轮排除一层,二叉搜索树的层数最小为logN(满二叉树),最大为 N(退化为链表)
空间复杂度 O ( N ) \rm{O(N)} O(N):最差情况下,即树退化为链表时,递归深度达到树的层数N


三、整体代码

迭代算法整体代码如下

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
    while(root){
        if(p->val < root->val && q->val < root->val){
            root = root->left;
        }
        else if(p->val > root->val && q->val > root->val){
            root = root->right;
        }
        else{
            break;
        }   
    } 
    
    return root;
}

运行,测试通过
在这里插入图片描述


递归算法整体代码如下

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
    if(p->val < root->val && q->val < root->val){
        return lowestCommonAncestor(root->left, p, q);
    }
    if(p->val > root->val && q->val > root->val){
        return lowestCommonAncestor(root->right, p, q);
    }
    return root;
}

运行,测试通过
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知初与修一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值