码迷,mamicode.com
首页 > 其他好文 > 详细

LeetCode-二叉树的最近公共祖先

时间:2021-06-17 16:40:10      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:code   ||   怎么   相交   有一个   调用   子节点   pre   函数返回   

二叉树的最近公共祖先

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

遇到任何递归型的问题,无非就是灵魂三问

1、这个函数是干嘛的

情况 1,如果pq都在以root为根的树中,函数返回的即使pq的最近公共祖先节点。

情况 2,那如果pq都不在以root为根的树中怎么办呢?函数理所当然地返回null呗。

情况 3,那如果pq只有一个存在于root为根的树中呢?函数就会返回那个节点。

2、这个函数参数中的变量是什么的是什么

函数参数中的变量是root,因为根据框架,lowestCommonAncestor(root)会递归调用root.leftroot.right;至于pq,我们要求它俩的公共祖先,它俩肯定不会变化的。

把「以root为根」转移成「以root的子节点为根」,不断缩小问题规模

3、得到函数的递归结果,你应该干什么

先想 base case,如果root为空,肯定得返回null。如果root本身就是p或者q,比如说root就是p节点吧,如果q存在于以root为根的树中,显然root就是最近公共祖先;即使q不存在于以root为根的树中,按照情况 3 的定义,也应该返回root节点。

以上两种情况的 base case 就可以把框架代码填充一点了:

TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    // 两种情况的 base case
    if (root == null) return null;
    if (root == p || root == q) return root;

    TreeNode left = lowestCommonAncestor(root.left, p, q);
    TreeNode right = lowestCommonAncestor(root.right, p, q);
}

用递归调用的结果leftright来搞点事情。根据刚才第一个问题中对函数的定义,我们继续分情况讨论:

情况 1,如果pq都在以root为根的树中,那么leftright一定分别是pq(从 base case 看出来的)。

情况 2,如果pq都不在以root为根的树中,直接返回null

情况 3,如果pq只有一个存在于root为根的树中,函数返回该节点。

leftright非空,分别是pq,可以说明root是它们的公共祖先,但能确定root就是「最近」公共祖先吗?

这就是一个巧妙的地方了,因为这里是二叉树的后序遍历啊!前序遍历可以理解为是从上往下,而后序遍历是从下往上,就好比从pq出发往上走,第一次相交的节点就是这个root,所以这个root当然是最近公共祖先了

public class LowestCommonAncestor {

    public class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode(int x) { val = x; }
    }

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // base case
        if(root == null) {
            return null;
        }
        // 如果遍历到的根节点为p或者q,说明在父节点的子树下找到了该节点,所以返回该父节点
        if(p==root||q==root) {
            return root;
        }
        // 后序遍历,递归调用,left是在父节点的左子树中找到的p节点或者q节点或者空节点,right同理
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        // 如果左子树和右子树都找到了p,q节点,说明父节点就是最近公共祖先,因为是后序遍历,所以能确保该父节点就是最近的祖先
        if(left!=null&&right!=null) {
            return root;
        }
        // 如果左子树和右子树都没有找到p,q节点,说明p,q节点和该父节点没关系,返回null,表示该父节点的子树下不包含p,q节点
        if(left==null&&right==null) {
            return null;
        }
        // 在上边条件都不满足的情况下,说明在该父节点下只找到了p或者q其中一个节点,返回这个找到的节点即可,
        // 如果是最外层的递归调用可能是因为另一个节点在这个节点的子树下,已经遍历找到了这个节点,就直接返回了没有再去找另一个节点,或者是两个节点都在左子树的某一个父节点下,所以右子树没有找到节点,这里当然返回这两个节点所在树的子调用里的父节点也就是现在返回的left了,右子树同理
        return left!=null?left:right;
    }
}

LeetCode-二叉树的最近公共祖先

标签:code   ||   怎么   相交   有一个   调用   子节点   pre   函数返回   

原文地址:https://www.cnblogs.com/RealGang/p/14891288.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!