二叉树的公共祖先问题

二刷随想录的时候发现,二叉树的公共祖先问题有一个点很巧妙,在这里记录下来,也作为之后复习用的笔记。

记录内容就以随想录的两道题为主。

1、二叉树的最近公共祖先

对应题目236. 二叉树的最近公共祖先 - 力扣(LeetCode)

最近公共祖先的概念不难理解,重点其实就在如何判断一个节点是要找的节点的公共祖先。

如果是,怎么判断是最近的公共祖先。

当使用后序遍历时,如果一个节点的孩子节点同时包含两个目标节点,那么该节点就是目标节点的公共祖先,且一定是最近的公共祖先。

为什么想到用后序遍历,因为中逻辑要处理左右孩子的返回结果,所以一定要使用后序遍历。

那么之后就是处理中逻辑,中逻辑无非就是三种情况:

1、左右孩子返回结果都为空,说明都不包含目标节点,向上返回null。

2、左右孩子返回结果只有一个为空,那么向上返回不为空的结果,因为不为空的结果包含了目标节点。

3、左右节点都不为空,说明该节点的孩子中包含了所有目标节点,该节点就是最近公共祖先,向上返回该节点。

一开始会发现,这三种情况当中,没有包含如果目标节点本身是公共祖先的情况,那么其实在if的终止条件里,已经有包含了这种情况了。

因为if是遍历到节点就直接判断,因此可以认为是自顶向下判断,当遍历到目标节点,并且该节点就是公共祖先时,直接向上返回当前节点,所以结果是完全正确的。

即使还有一个目标节点没有遍历,也无关紧要了,这里是我认为很妙的一个点。

搜索的大致过程如下

代码如下

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // 遇到pq就返回 
        // 其实这里就包括了祖先是自己的情况了 
        // 如果祖先是自己 那么if是自上而下判断 判断到root是p或q 此时p或q就是祖先 会直接返回 
        // 那么另外一个是否遍历到也无关紧要了
        if (root == null || root == p || root == q) return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);

        // 返回都不为空 则当前节点就是祖先
        if (left != null && right != null) return root;
        else if (left == null) return right;   // 其中一个不为空 返回不为空的那个
        else if (right == null) return left;
        return null;
    }
}

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

对应题目235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

说到搜索二叉树,那么必然就是要提到有序性了。

因为搜索树的有序性,如果某个节点的数值在目标节点的数值范围之内,那么该节点一定是最近公共祖先,可以直接返回。

那么直接处理中逻辑就可以了,不需要处理左右孩子的返回结果,遍历顺序无要求。

代码如下

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // root == p || root == q条件不能去掉 包含了公共祖先是自己的情况
        if (root == null || root == p || root == q) return root;

        // root.val在pq的范围内 一定是公共祖先 且是最近的
        if (root.val < Math.max(p.val, q.val) && root.val > Math.min(p.val, q.val)) {
            return root;
        }
        else if (root.val < Math.min(p.val, q.val)) {
            return lowestCommonAncestor(root.right, p, q);
        }
        return lowestCommonAncestor(root.left, p, q);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值