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

题目描述:

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

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

解题思路:

1、迭代:

      根据题目所描述的“最近公共祖先”的定义,“最近公共祖先”的定义包括了两点,一是该节点是公共祖先节点;二是该节点的左右孩子都不是公共祖先

      当root为p,q的最近公共祖先,则可能存在以下情况:

(1)p和q节点在root的子树,且分别在左右子树;

(2)p = root,q在root的子树中;

(3)q = root, p在root的子树中;

      根据上述分析,当root不是p和q节点的最近公共祖先的情况只有一种,即节点p和q在root的同侧子树中(即同时在左子树或者同时在右子树),这种情况最近公共祖先可能存在于root的同侧孩子节点。

      因此,只需要循环判断root不是最近公共节点的情况,然后不断更新root即可。

注1: 在判断p和q节点在root的哪一侧时可以借助二叉搜索树的特性:left.val < root.val < right.val,同时需要注意所有节点的值都是唯一的。

2、迭代(减少判断次数):

      这种解法的整体思路和解法1的思路是一样的,只是在迭代之前将q.val更新为最大,即q.val > p.val。这样,在后面的判断中就可以减少判断次数。

3、递归:

     这种解法其实是迭代的递归写法,思路是一样的,具体可参见实现代码。

时间复杂度和空间复杂度: 时间复杂度都为O(N),其中解法1和解法2的空间复杂度为O(1),解法3的空间复杂度为O(N)

实现代码:

	//解法1:迭代
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(p == null || q == null)
            return root;
        while(root != null){
            if(root.val > p.val && root.val > q.val)
                root = root.left;
            else if(root.val < p.val && root.val < q.val)
                root = root.right;
            else
                break;
        }
        return root;
    }

    //解法2:迭代(减少一次判断)
    public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
        if(p == null || q == null)
            return root;
        if(p.val > q.val){//保持q.val > p.val
            TreeNode temp = p;
            p = q;
            q = temp;
        }
        while(root != null){
            if(root.val > q.val)
                root = root.left;
            else if(root.val < p.val)
                root = root.right;
            else
                break;
        }
        return root;
    }

    //解法3:递归
    public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
        if(p == null || q == null)
            return root;
        if(root != null){
            if(root.val > p.val && root.val > q.val)
                return lowestCommonAncestor2(root.left, p, q);
            else if(root.val < p.val && root.val < q.val)
                return lowestCommonAncestor2(root.right, p, q);
            else
                return root;
        }
        return null;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值