LeetCode 865. Smallest Subtree with all the Deepest Nodes【树,DFS,BFS,哈希表】1534

这篇具有很好参考价值的文章主要介绍了LeetCode 865. Smallest Subtree with all the Deepest Nodes【树,DFS,BFS,哈希表】1534。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

给定一个根为 root 的二叉树,每个节点的深度是 该节点到根的最短距离

返回包含原始树中所有 最深节点最小子树

如果一个节点在 整个树 的任意节点之间具有最大的深度,则该节点是 最深的

一个节点的 子树 是该节点加上它的所有后代的集合。

示例 1:
LeetCode 865. Smallest Subtree with all the Deepest Nodes【树,DFS,BFS,哈希表】1534,树-二叉树,# BFS/DFS,leetcode,深度优先

输入:root = [3,5,1,6,2,0,8,null,null,7,4]
输出:[2,7,4]
解释:
我们返回值为 2 的节点,在图中用黄色标记。
在图中用蓝色标记的是树的最深的节点。
注意,节点 532 包含树中最深的节点,但节点 2 的子树最小,因此我们返回它。

示例 2:

输入:root = [1]
输出:[1]
解释:根节点是树中最深的节点。

示例 3:

输入:root = [0,1,3,null,2]
输出:[2]
解释:树中最深的节点为 2 ,有效子树为节点 210 的子树,但节点 2 的子树最小。

提示:

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

注意: 本题与力扣 1123 重复:https://leetcode-cn.com/problems/lowest-common-ancestor-of-deepest-leaves


解法1 递归

LeetCode 865. Smallest Subtree with all the Deepest Nodes【树,DFS,BFS,哈希表】1534,树-二叉树,# BFS/DFS,leetcode,深度优先
看上图(示例 1),这棵树的节点 3 , 5 , 2 3,5,2 3,5,2 都是最深叶节点 7 , 4 7,4 7,4 的公共祖先,但只有节点 2 2 2 是最近的公共祖先。

如果我们要找的节点只在左子树中,那么最近公共祖先也必然只在左子树中。对于本题,如果左子树的最大深度比右子树的大,那么最深叶结点就只在左子树中,所以最近公共祖先也只在左子树中。反过来说,如果右子树的最大深度大于左子树,那么最深叶结点就只在右子树中,所以最近公共祖先也只在右子树中。

如果左右子树的最大深度一样呢?当前节点一定是最近公共祖先吗?不一定。比如节点 1 1 1 的左右子树最深叶节点 0 , 8 0,8 0,8 的深度都是 2 2 2 ,但该深度并不是全局最大深度,所以节点 1 1 1 并不能是答案。

根据以上讨论,正确做法如下:

  • 递归这棵二叉树,同时维护全局最大深度 maxDepth \textit{maxDepth} maxDepth
  • 在「」的时候往下传 d e p t h depth depth ,用来表示当前节点的深度
  • 在「」的时候往上传当前子树最深叶节点的深度
  • 设左子树最深叶节点的深度为 leftMaxDepth \textit{leftMaxDepth} leftMaxDepth ,右子树最深叶节点的深度为 rightMaxDepth \textit{rightMaxDepth} rightMaxDepth 。如果 leftMaxDepth = rightMaxDepth = maxDepth \textit{leftMaxDepth}=\textit{rightMaxDepth}=\textit{maxDepth} leftMaxDepth=rightMaxDepth=maxDepth ,那么更新答案为当前节点。注意这并不代表我们找到了答案,如果后面发现了更深的叶节点,那么答案还会更新。
class Solution {
public:
    TreeNode *subtreeWithAllDeepest(TreeNode *root) {
        TreeNode *ans = nullptr;
        int max_depth = -1; // 全局最大深度
        function<int(TreeNode*, int)> dfs = [&](TreeNode *node, int depth) {
            if (node == nullptr) {
                max_depth = max(max_depth, depth); // 维护全局最大深度
                return depth;
            }
            int left_max_depth = dfs(node->left, depth + 1); // 获取左子树最深叶节点的深度
            int right_max_depth = dfs(node->right, depth + 1); // 获取右子树最深叶节点的深度
            if (left_max_depth == right_max_depth && left_max_depth == max_depth)
                ans = node;
            return max(left_max_depth, right_max_depth); // 当前子树最深叶节点的深度
        };
        dfs(root, 0);
        return ans;
    }
};

复杂度分析:

  • 时间复杂度: O ( n ) \mathcal{O}(n) O(n) 。每个节点都会恰好访问一次。
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n) 。最坏情况下,二叉树是一条链,递归需要 O(n)\mathcal{O}(n)O(n) 的栈空间。

解法2 自底向上

也可以不用全局变量,而是把每棵子树都看成是一个「子问题」,即对于每棵子树,我们需要知道:

  • 这棵子树最深叶结点的深度。这里是指叶子在这棵子树内的深度,而不是在整棵二叉树的视角下的深度。相当于这棵子树的高度
  • 这棵子树的最深叶结点的最近公共祖先 lca \textit{lca} lca

分类讨论:

  • 设子树的根节点为 n o d e node node n o d e node node 的左子树的高度为 leftHeight \textit{leftHeight} leftHeight n o d e node node 的右子树的高度为 rightHeight \textit{rightHeight} rightHeight
  • 如果 l e f t H e i g h t > r i g h t H e i g h t leftHeight>rightHeight leftHeight>rightHeight ,那么子树的高度为 leftHeight + 1 \textit{leftHeight} + 1 leftHeight+1 lca \textit{lca} lca 是左子树的 lca \textit{lca} lca
  • 如果 leftHeight < rightHeight \textit{leftHeight} < \textit{rightHeight} leftHeight<rightHeight ,那么子树的高度为 r i g h t H e i g h t + 1 rightHeight+1 rightHeight+1 l c a lca lca 是右子树的 l c a lca lca
  • 如果 leftHeight = rightHeight \textit{leftHeight} = \textit{rightHeight} leftHeight=rightHeight ,那么子树的高度为 leftHeight + 1 \textit{leftHeight} + 1 leftHeight+1 l c a lca lca 就是 n o d e node node 。反证法:如果 l c a lca lca 在左子树中,那么 l c a lca lca 不是右子树的最深叶结点的祖先,这不对;如果 l c a lca lca 在右子树中,那么 l c a lca lca 不是左子树的最深叶结点的祖先,这也不对;如果 l c a lca lca n o d e node node 的上面,那就不符合「最近」的要求。所以 l c a lca lca 只能是 n o d e node node
class Solution {
    pair<int, TreeNode*> dfs(TreeNode *node) {
        if (node == nullptr)
            return {0, nullptr};
        auto [left_height, left_lca] = dfs(node->left);
        auto [right_height, right_lca] = dfs(node->right);
        if (left_height > right_height) // 左子树更高
            return {left_height + 1, left_lca};
        if (left_height < right_height) // 右子树更高
            return {right_height + 1, right_lca};
        return {left_height + 1, node}; // 一样高
    }

public:
    TreeNode *subtreeWithAllDeepest(TreeNode *root) {
        return dfs(root).second;
    }
};

复杂度分析:

  • 时间复杂度: O ( n ) \mathcal{O}(n) O(n) 。每个节点都会恰好访问一次。
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n) 。最坏情况下,二叉树是一条链,递归需要 O ( n ) \mathcal{O}(n) O(n) 的栈空间。

更简洁的写法是:文章来源地址https://www.toymoban.com/news/detail-700484.html

class Solution {
public:
    int depth[1010];
    TreeNode* subtreeWithAllDeepest(TreeNode* root) {
        if (root == nullptr) return nullptr;
        TreeNode* left = root->left, *right = root->right;
        TreeNode* lcaLeft = subtreeWithAllDeepest(root->left), *lcaRight = subtreeWithAllDeepest(root->right);
        int dl = left ? depth[left->val] : 0, dr = right ? depth[right->val] : 0;
        depth[root->val] = max(dl, dr) + 1;
        if (dl > dr) return lcaLeft;
        if (dr > dl) return lcaRight;
        return root;
    }
};

到了这里,关于LeetCode 865. Smallest Subtree with all the Deepest Nodes【树,DFS,BFS,哈希表】1534的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 解决File ~ could only be written to 0 of the 1 minReplication nodes.

    在通过javaApi上传本地文件时出现以下错误,主要原因是: File /test3.txt could only be written to 0 of the 1 minReplication nodes. There are 1 datanode(s) running and 1 node(s) are excluded in this operation. 但是之前还能解决向hdfs创建目录,为什么不能上传文件嘞?按理说权限不应该有问题,那具体是什么

    2023年04月08日
    浏览(65)
  • K8s in Action 阅读笔记——【13】Securing cluster nodes and the network

    Pod中的容器通常在不同的Linux名称空间下运行,这使得它们的进程与其他容器或节点默认名称空间下运行的进程隔离开来。 例如,我们学习到每个Pod都拥有自己的IP和端口空间,因为它使用其自己的网络名称空间。同样,每个Pod也拥有自己的进程树,因为它有自己的PID名称空

    2024年02月11日
    浏览(32)
  • K8s in Action 阅读笔记——【14】Securing cluster nodes and the network

    迄今为止,创建了 Pod 而不考虑它们允许消耗多少 CPU 和内存。但是,正如将在本章中看到的那样,设置 Pod 预期消耗和允许消耗的最大数量是任何 Pod 定义的重要部分。设置这两组参数可以确保 Pod 只占用 Kubernetes 集群提供的资源中的份额,并且还影响 Pod 在集群中的调度方式

    2024年02月08日
    浏览(30)
  • All the stories begin at installation

    Before installation, there are some key points about Conan: “Conan is a dependency and package manager for C and C++ languages.” “With full binary management, Conan can create and reuse any number of different binaries (for different configurations like architectures, compiler versions, etc.) for any number of different versions of a package, using exa

    2024年02月20日
    浏览(26)
  • 【已解决】could only be written to 0 of the 1 minReplication nodes. There are 1 datanode(s) running and 1

    hadoop分布式集群搭建时出现的问题 将VMare中的网络连接方式改变即可。如图将默认的NAT模式切换为桥接模式,然后重启Slvae虚拟机,关闭Master集群,重启Master集群。 我在网上搜到的大部分解决的都是类似报错,即 但请注意,这种报错显示的是0个datanode,而我的报错显示是有

    2024年02月16日
    浏览(37)
  • Vector Search with OpenAI Embeddings: Lucene Is All You Need

    本文是LLM系列文章,针对《Vector Search with OpenAI Embeddings: Lucene Is All You Need》的翻译。 我们在流行的MS MARCO文章排名测试集上使用Lucene提供了一个可复制的、端到端的OpenAI嵌入向量搜索演示。我们工作的主要目标是挑战主流的说法,即专用向量存储是利用深度神经网络应用于搜

    2024年02月10日
    浏览(36)
  • 已解决ValueError: All arrays must be of the same length

    已解决(pandas创建DataFrame对象报错)ValueError: All arrays must be of the same length 粉丝群里面的一个粉丝用pandas创建DataFrame对象,但是发生了报错(跑来找我求助,然后顺利帮助他解决了,顺便记录一下希望可以帮助到更多遇到这个bug不会解决的小伙伴),报错信息和代码如下: 报

    2024年02月02日
    浏览(41)
  • Not All Features Matter:Enhancing Few-shot CLIP with Adaptive Prior Refinement

    APE是ICCV2023的一篇文章,也是我在这个领域里接触的第一篇文章,这里主要做一下记录。 论文链接:2304.01195.pdf (arxiv.org) 代码链接:yangyangyang127/APE: [ICCV 2023] Code for \\\"Not All Features Matter: Enhancing Few-shot CLIP with Adaptive Prior Refinement\\\" (github.com) 对于多模态任务而言,大量数据的获得

    2024年02月13日
    浏览(24)
  • 【Golang】排查 Build constraints exclude all the go files 的几个思路

    输出该问题时说明在 Go 语言的启动编译(Build)阶段,出现了编译问题,往往是 编译配置 的问题。可以通过以下思路去排查对应的错误。 (1)首先可以查看被排除的 Go 文件是否启用了 条件编译 ,通常的形式为在文件的首行添加(以 Linux 为例): // +build 会逐渐取代 //go

    2024年02月15日
    浏览(30)
  • 1021 Deepest Root (PAT甲级)

    1021. Deepest Root (25)-PAT甲级真题(图的遍历,dfs,连通分量的个数)_柳婼的博客-CSDN博客 柳婼的解法在这里,两次dfs,还是挺好玩的。 我的解法比较暴力,就是先用并查集算连通分量(这个其实还是dfs来算会更方便),如果只有一个连通分量,那deepest root一定在仅有一条arc的

    2024年02月15日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包