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

发布时间 2023-09-06 21:50:33作者: Owlwu

给你一个有根节点 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 重复:https://leetcode-cn.com/problems/smallest-subtree-with-all-the-deepest-nodes/


 

一开始看见找叶子节点,想到的是广度优先搜索,可以很方便地找到最深的叶子节点。然后需要找到公共祖先,于是想到了回溯。

先找到最深的叶子节点,然后层层往上回溯。当回溯时返回的 Set 的长度为 1 时,意味着此时就是答案。接下来就直接返回它即可。

class Solution {
    public TreeNode lcaDeepestLeaves(TreeNode root) {
        Set<TreeNode> set = new HashSet<>();
        set.add(root);
        Set<TreeNode> res = getRes(set);
        for (TreeNode node : res) {
            return node;
        }
        return null;
    }

    private Set<TreeNode> getRes(Set<TreeNode> set) {
        Set<TreeNode> leafSet = new HashSet<>();
        for (TreeNode node : set) {
            if (node.left != null) {
                leafSet.add(node.left);
            }
            if (node.right != null) {
                leafSet.add(node.right);
            }
        }
        if (leafSet.isEmpty()) {
            return new HashSet<>(set);
        }
        Set<TreeNode> res = getRes(leafSet);
        if (res.size() == 1) {
            return res;
        } else {
            Set<TreeNode> resSet = new HashSet<>();
            for (TreeNode node : set) {
                if (res.contains(node.left) || res.contains(node.right)) {
                    resSet.add(node);
                }
            }
            return resSet;
        }
    }
}

 优化:

可以用深度优先搜索。

递归,通过递来获取最深路径,通过归来判断是否是答案。

class Solution {
    private TreeNode res;
    private int maxDepth = -1; // 全局最大深度

    public TreeNode lcaDeepestLeaves(TreeNode root) {
        dfs(root, 0);
        return res;
    }

    private int dfs(TreeNode node, int depth) {
        if (node == null) {
            maxDepth = Math.max(depth, maxDepth);
            return depth;
        }
        // 左子树的最大深度
        int leftDepth = dfs(node.left, depth + 1);
        // 右子树的最大深度
        int rightDepth = dfs(node.right, depth + 1);
        // 如果左子树的最大深度等于右子树的最大深度并且左子树的深度等于当前的最大深度,则说明当前节点是当前已经走过的路径中的答案。
        // 可以想到,如果左子树深度和右子树深度不相等的话,当前节点绝对不可能是答案。
        // 如果之后最大深度更新了,当前答案也会随之更新。
        if (leftDepth == rightDepth && leftDepth == maxDepth) {
            res = node;
        }
        return Math.max(leftDepth, rightDepth);
    }
}