换根dp,LeetCode310. 最小高度树

一、题目

1、题目描述

树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。

给你一棵包含 n 个节点的树,标记为 0 到 n - 1 。给定数字 n 和一个有 n - 1 条无向边的 edges 列表(每一个边都是一对标签),其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间存在一条无向边。

可选择树中任何一个节点作为根。当选择节点 x 作为根节点时,设结果树的高度为 h 。在所有可能的树中,具有最小高度的树(即,min(h))被称为 最小高度树 。

请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。

树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。

2、接口描述

cpp
class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
        
    }
};

python3

3、原题链接

310. 最小高度树


二、解题报告

1、思路分析

在不使用最小高度树结论的情况下,即不使用拓扑排序的情况下,我们怎样思考这个问题?

朴素思路,暴力计算每个点为根时的高度,然后就能求出最小高度了

这样需要O(n^2)的时间复杂度,会爆掉

那么如何优化?

我们发现上图中根从x变到y的过程中,x的除去y的子树高度不变,y除去x的子树高度不变

而且x和y的高度变化具有递推关系,也就是说我们可以根据x、y的原高度,计算出换根后的新高度

假设换根前,x子树中最大高度first和次大高度second

那么如果,换根前y就是first,那么换根后x变成second + 1,否则还是first + 1

而y的其它子树高度不变

这也就是说,我们只需要一次dfs以某个节点为根的所有节点的高度,然后进行换根dp就行了

每次换根后,新根只有一个节点的高度需要重新计算这是O(1)就能解决的,然后新根的高度就是所有子树最大高度+1

无论是第一次dfs还是换根dp,每个节点都最多访问一次,所以整体时间复杂度O(n)

2、复杂度

时间复杂度: O(n)空间复杂度:O(n)

3、代码详解

cpp
class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
        vector<int> dep0(n), dep1(n);
        vector<vector<int>> g(n);
        for(auto& p : edges)
            g[p[0]].emplace_back(p[1]), g[p[1]].emplace_back(p[0]);
        function<void(int, int)> dfs0 = [&](int x, int fa){
            dep0[x] = 1;
            for(int y : g[x])
                if(y != fa)
                    dfs0(y, x), dep0[x] = max(dep0[x], dep0[y] + 1);
        };
        function<void(int)> dfs1 = [&](int x){
            int first = 0, second = 0;
            for(int y : g[x])
                if(dep0[y] > first) second = first, first = dep0[y];
                else if(dep0[y] > second) second = dep0[y];
            dep1[x] = first + 1;
            for(int y : g[x])
                if(!dep1[y])
                    dep0[x] = dep0[y] == first ? second + 1 : first + 1, dfs1(y);
        };
        dfs0(0, -1), dfs1(0);
        int mi = *min_element(dep1.begin(), dep1.end());
        vector<int> ret;
        for(int i = 0; i < n; i++)
            if(dep1[i] == mi) ret.emplace_back(i);
        return ret;
    }
};
​python3
class Solution:
    def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
        dep0, dep1 = [0] * n, [0] * n
        g = [[] for _ in range(n)]
        for x, y in edges:
            g[x].append(y)
            g[y].append(x)
        def dfs0(x: int, fa: int):
            dep0[x] = 1
            for y in g[x]:
                if y != fa:
                    dfs0(y, x)
                    dep0[x] = max(dep0[y] + 1, dep0[x])
        def dfs1(x: int):
            first, second = 0, 0
            for y in g[x]:
                if dep0[y] > first:
                    second = first
                    first = dep0[y]
                elif dep0[y] > second:
                    second = dep0[y]
            dep1[x] = first + 1
            for y in g[x]:
                if not dep1[y]:
                    dep0[x] = first + 1 if dep0[y] != first else second + 1
                    dfs1(y)
        dfs0(0, -1)
        dfs1(0)
        mi = min(dep1)
        return [i for i in range(n) if dep1[i] == mi]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/463892.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自媒体人的超级宝典

这个10块钱的小报童还有谁没买&#xff1f; 你可别等到它涨到19.9的时候来问我有没有优惠 昨天正式发售就已经2300人了&#xff0c;之前可是几个小时就涨了400多人&#xff0c;照这个速度下去&#xff0c;明天就要涨价了。 说实话&#xff0c;我看了里面的内容&#xff0c;觉…

Linux网络编程: 以太网帧Frame/ARP/RARP详解

一、TCP/IP五层模型 物理层&#xff08;Physical Layer&#xff09;&#xff1a;物理层是最底层&#xff0c;负责传输比特流&#xff08;bitstream&#xff09;以及物理介质的传输方式。它定义了如何在物理媒介上传输原始的比特流&#xff0c;例如通过电缆、光纤或无线传输等。…

SAP Activate项目管理方法论路线图

SAP Activate 是 SAP 推出的一种基于敏捷方法论的灵活、快速且引导式的实施方法论&#xff0c;专为加速SAP S/4HANA和其他SAP解决方案的部署而设计。这个方法论结合了最佳实践、引导配置和方法论本身的强大能力&#xff0c;以确保项目的快速实施和成功部署。SAP Activate的核心…

ffmpeg 滤镜实现不同采样率多音频混音

音频混音在音视频开发中是十分重要的一个环节,所谓音频混音就是将所有需要混音的数据相加得到混音数据,然后通过某个算法进行非法数据的处理;例如相加数值超过最大值,最小值等! 在实际的音频开发中,要实现混音的流程如下: 因此我们的编码实现就分为五部分:寻找…

22-分支和循环语句_while语句(下)(初阶)

该代码输出什么&#xff1f; int main() {char ch \0;while ((ch getchar()) ! EOF){if (ch < 0 || ch>9){continue;}putchar(ch);}return 0; } 结果&#xff1a;该代码只打印数字字符 附&#xff1a;ASCII码表

Python基础入门 --- 5.函数

文章目录 Python基础入门5.函数5.1 基本定义5.2 传入参数5.3 返回值5.3.1 None类型 5.4 说明文档5.5 嵌套调用 Python基础入门 5.函数 定义&#xff1a;可重复使用&#xff0c;用来实现特定功能的代码段。 # 不使用内置函数len&#xff0c;统计字符串的长度 str "Hell…

南卡罗来纳州历史和文化经济地理和自然政治和社会教育1. 加州大学公布2024年秋季入学新生和转学申请数据2. 2024考研国家线公布路德会信徒核心信仰礼拜和

目录 南卡罗来纳州 历史和文化 经济 地理和自然 政治和社会 教育 1. 加州大学公布2024年秋季入学新生和转学申请数据 2. 2024考研国家线公布 路德会信徒 核心信仰 礼拜和实践 分布 社会和文化影响 约翰塞巴斯蒂安巴赫 生平简介 音乐风格和作品 遗产和影响 …

AXI Lite协议详解

AXI Lite协议详解 axi&#xff08;Advanced eXtensible Interface&#xff09;是一种总线协议&#xff0c;该协议是ARM公司提出的amba&#xff08;Advanced Microcontroller Bus Architecture&#xff09;3.0协议中最重要的部分&#xff0c;是一种面向高性能、高带宽、低延迟的…

C++17之std::variant

1. std::variant操作 如下列出了为std:: variable <>提供的所有操作。

Docker 学习笔记一

一、什么是docker Docker 是一个基于轻量级虚拟化技术的容器&#xff0c;整个项目基于Go语言开发&#xff1b;Docker是一个C/S架构&#xff0c;后端众多模块各司其职&#xff0c;docker的daemon是运行在主机上通过client可以进行通信。 docker 由三部分组成&#xff1a;镜像(…

Rust 构建开源 Pingora 框架可以与nginx媲美

一、概述 Cloudflare 为何弃用 Nginx&#xff0c;选择使用 Rust 重新构建新的代理 Pingora 框架。Cloudflare 成立于2010年&#xff0c;是一家领先的云服务提供商&#xff0c;专注于内容分发网络&#xff08;CDN&#xff09;和分布式域名解析。它提供一系列安全和性能优化服务…

Figure 01掀起了具身智能的崭新篇章

在人工智能的发展历程中&#xff0c;OpenAI始终扮演着创新的先锋角色。最近&#xff0c;他们与Figure公司的合作成果尤为引人注目&#xff0c;这一合作将多模态大模型技术成功应用于Figure 01机器人的开发中&#xff0c;为人类与机器的互动开辟了全新的时代。该机器人不仅能够与…

innovus中path group 的策略和应用(上)

在所有的后端工具里边&#xff0c;有三个重要的引擎&#xff1a;auto-place&#xff0c;CTS&#xff0c;auto-route三个。这里边的auto-place是决断了整个设计时序的基点。由于&#xff0c;auto-place的动作是在设计的preCTS阶段&#xff0c;所以这里的设计时序就是广义上说的&…

HDFSDATANODE数据传输详解

本文主要阐述datanode中一个socket连接接收字节流的构成&#xff0c;帮助datanode的接收与处理数据。注意hadoop版本为3.1.1。 写在前面 Datanode本质上也是TCPServer&#xff0c;一般的TCPServer接到客户端请求以后会分配一个线程处理&#xff0c;对于Datanode而言&#xff…

npm、nodejs和vue之间关系和区别介绍

本文讲解npm、Node.js和Vue.js这三者之间的关系和区别&#xff0c;以及它们各自的特点。 首先&#xff0c;让我们来了解一下Node.js。 **Node.js** 是一个开源的服务器端运行环境&#xff0c;它允许开发者使用JavaScript来编写服务器端的代码。在传统的Web开发中&#…

[ROS 系列学习教程] rosbag Python API

ROS 系列学习教程(总目录) 本文目录 1. 构造函数与关闭文件2. 属性值3. 写bag文件内容4. 读bag文件内容5. 将bag文件缓存写入磁盘6. 重建 bag 文件索引7. 获取bag文件的压缩信息8. 获取bag文件的消息数量9. 获取bag文件记录的起止时间10. 获取话题信息与消息类型 rosbag 的 Pyt…

【Java探索之旅】运算符解密 位运算,移位运算

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java入门到精通 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、位运算符1.1 按位与 &1.2 按位或 |1.3 按位取反 ~1.4 按位异或^ 二、移位运…

快速排序算法,简洁,易懂

目录 代码实现&#xff08;java&#xff09;&#xff1a; 一、首元素作为基准值 图&#xff1a; ​编辑 基本思路&#xff1a; 代码&#xff1a; 代码补充说明&#xff1a; 二、中间元素作为基准值 代码&#xff1a; 参考学习文章&#xff1a; 今天我们不刷力扣了&#xff0c;…

Java Web项目—餐饮管理系统Day07-套餐管理(二)

文章目录 1. 套餐的分页查询2. 更新套餐![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/209298cf3b4349c5a2fed56a3d33350e.png)第一步, 依据套餐id查询到套餐的基本信息以及关联菜品信息.第2步, 将请求数据进行保存(更新). 3. 批量的停售启售 这部分开发剩下的部分…

CSS Module

CSS Module的作用&#xff1a;将CSS样式作用域限制在特定的组件范围内&#xff0c;以避免全局样式污染和命名冲突。 Vue中如何实现样式模块…