最深叶节点的最近公共祖先

122 阅读2分钟

1123. 最深叶节点的最近公共祖先 - 力扣(LeetCode)

给你一个有根节点  root  的二叉树,返回它  最深的叶节点的最近公共祖先 。

回想一下:

  • 叶节点 是二叉树中没有子节点的节点
  • 树的根节点的  深度  为  0,如果某一节点的深度为  d,那它的子节点的深度就是  d+1
  • 如果我们假定 A 是一组节点  S  的 最近公共祖先S  中的每个节点都在以 A 为根节点的子树中,且 A  的深度达到此条件下可能的最大值。

示例 1:

输入: root = [3,5,1,6,2,0,8,null,null,7,4]
输出: [2,7,4]
解释: 我们返回值为 2 的节点,在图中用黄色标记。
在图中用蓝色标记的是树的最深的节点。
注意,节点 6、0 和 8 也是叶节点,但是它们的深度是 2 ,而节点 7 和 4 的深度是 3 。

示例 2:

输入: root = [1]
输出: [1]
解释: 根节点是树中最深的节点,它是它本身的最近公共祖先。

示例 3:

输入: root = [0,1,3,null,2]
输出: [2]
解释: 树中最深的叶节点是 2 ,最近公共祖先是它自己。

提示:

  • 树中的节点数将在  [1, 1000]  的范围内。
  • 0 <= Node.val <= 1000
  • 每个节点的值都是  独一无二  的。

注意: 本题与力扣 865 重复:leetcode-cn.com/problems/sm…

思路

看到本题,我第一个想到的就是找出所有从跟节点到最深叶子节点的路径,然后比较这些路径找出最后一个相同的节点,就是我们要求解的节点。用深度优先遍历所有从跟到叶子节点的路径并筛选出其中的最长路径。然后比较这些路径,找出最后一个相同的节点即可。代码如解法一

上面的解法我们不仅求出了最深叶节点的最近公共祖先,还找出了所有的最长路径,多少有点儿浪费。我们分析发现下面几条事实

  • 如果根节点没有左右节点,根节点就是我们要求的节点
  • 如果跟节点只有左节点,我们要求的节点一定在跟节点的左子树中,继续以左节点作为跟节点求解。
  • 如果跟节点只有右节点,我们要求的节点一定在跟节点的右子树中,继续以右节点作为跟节点求解。
  • 如果跟节点既有左节点,又有右节点,分别求左右子树的最深叶子节点的层数,记为 left 和 right
    • 如果 left === right,左右子树都有最深的叶子节点,跟节点就是我们要求的解。
    • 如果 left > right, 最深叶子节点在左子树中,继续以左节点作为跟节点求解。
    • 如果 right > left, 最深叶子节点在右子树中,继续以右节点作为跟节点求解。

代码如解法二

解题

解法一

/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var lcaDeepestLeaves = function (root) {
  let nodes = [];
  let max = 0;
  const dfs = (node, parents) => {
    parents.push(node);

    if (node.left) {
      dfs(node.left, [...parents]);
    }
    if (node.right) {
      dfs(node.right, [...parents]);
    }
    if (parents.length > max) {
      nodes = [parents];
      max = parents.length;
    } else if (parents.length === max) {
      nodes.push(parents);
    }
  };
  dfs(root, []);
  let res = root.val;
  for (let i = 0; i < max; i++) {
    let same = true;
    for (let j = 1; j < nodes.length; j++) {
      same = nodes[j - 1][i] === nodes[j][i];
      if (!same) {
        break;
      }
    }
    if (same) {
      res = nodes[0][i];
    }
  }
  return res;
};

解法二

/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var lcaDeepestLeaves = function (root) {
  const dfs = (node, level) => {
    if (!node) {
      return { level };
    }

    const res1 = dfs(node.left, level + 1);
    const res2 = dfs(node.right, level + 1);
    if (res1.level > res2.level) {
      return res1;
    } else if (res1.level < res2.level) {
      return res2;
    } else {
      return { level: res1.level, node };
    }
  };
  return dfs(root, 0);
};