[路飞]_LeetCode_面试题 04.08. 首个共同祖先

105 阅读2分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战

题目

设计并实现一个算法,找出二叉树中某两个节点的第一个共同祖先。不得将其他的节点存储在另外的数据结构中。注意:这不一定是二叉搜索树。

例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

     3
    /   \
  5      1
 / \      / \
6   2  0  8
     / \
   7    4

示例 1:

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

示例 2:

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

说明:

所有节点的值都是唯一的。
pq 为不同节点且均存在于给定的二叉树中。

来源:力扣(LeetCode)leetcode-cn.com/problems/fi…

解题思路

  1. 深度优先的方式遍历二叉树查找两个节点;
  2. 要找的两个节点可能有 3 种存在方式:
  • 第一种情况:两个节点在根节点的左右两棵子树中,根节点就是首个公共祖先;
  • 第二种情况:如果左子树找到其中一个,右子树中没找到,说明公共祖先在左子树中;
  • 第三种情况:如果右子树找到其中一个,左子树中没找到,说明公共祖先在右子树中;

列如从下面的树中找 7 和 4 的首个公共祖先。

     3
    /   \
  5      1
 / \      / \
6   2  0  8
     / \
   7    4

从这课树中找到 7 和 4 的首个公共祖先。

  • 2 的左、右子树都找到了节点,2 就是首个公共祖先;
  • 2 的父节点 5,左边没有找到节点,右边找到了节点,则返回右边的 2;
  • 5 的父节点 3,左边找到了节点,右边没有找到节点,则返回左边的 2;
  • 3 是最后的根节点,因此 2 就是首个共同祖先;

代码实现

var lowestCommonAncestor = function (root, p, q) {
    //如果根节点为空,或根节点等于 p、q,则返回根节点
    if (!root || root === p || root === q) return root

    //从左子树中找两个节点
    const left = lowestCommonAncestor(root.left, p, q)
    //从右子树中找两个节点
    const right = lowestCommonAncestor(root.right, p, q)

    //如果左右两棵子树分别找到了两个节点,当前根节点就是共同祖先
    //如果左子树遍历的结果不为空,说明左子树中存在一个节点,则返回左子树结果
    //如果右子树遍历的结果不为空,说明右子树中存在一个节点,则返回右子树结果
    return left && right ? root : left ? left : right
};

如有错误欢迎指出,欢迎一起讨论!