LeetCode236.二叉树的最近公共祖先

180 阅读2分钟

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

二叉树的最近公共祖先

题目

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

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

image.png

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3

image.png

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

image.png

解法

首先寻找两个节点的公共祖先,我们第一个需要想到的是要自底向上查找,而二叉树的回溯就是自底向上,在二叉树的三种遍历中,后序遍历是天然的回溯过程,最先处理的一定是叶子节点。而判断一个节点是否是另外两个节点q和p的公共祖先的条件如下:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。

递归三要素:

  • 递归函数的参数以及返回值:参数是当前层递归的根节点和要查找的p,q节点,返回值是TreeNode类型,也就是节点
  • 递归的单层逻辑:如果该层递归的根节点为空,或者等于p或q,那么返回根节点给上一层,如果不是以上情况,对左,右子树递归查找是否含有p,q节点,如果左右子树分别存在p,q,那么该根节点为最近公共祖先(因为后序遍历是自底向上的),如果左子树存在p,q就返回左子节点,右子树存在p,q就返回右子节点。
var lowestCommonAncestor = function(root, p, q) {
    // 使用递归的方法
    // 需要从下到上,所以使用后序遍历
    // 1. 确定递归的函数
    const travelTree = function(root,p,q) {
        // 2. 确定递归终止条件
        if(root === null || root === p||root === q) {
            return root;
        }
        // 3. 确定递归单层逻辑
        let left = travelTree(root.left,p,q);
        let right = travelTree(root.right,p,q);
        if(left !== null&&right !== null) {
            return root;
        }
        if(left === null) {
            return right;
        }
        return left;
    }
   return  travelTree(root,p,q);
};