【二叉树 C++DFS】2458. 移除子树后的二叉树高度

本文涉及知识点

二叉树 C++DFS

LeetCode 2458. 移除子树后的二叉树高度

给你一棵 二叉树 的根节点 root ,树中有 n 个节点。每个节点都可以被分配一个从 1 到 n 且互不相同的值。另给你一个长度为 m 的数组 queries 。
你必须在树上执行 m 个 独立 的查询,其中第 i 个查询你需要执行以下操作:
从树中 移除 以 queries[i] 的值作为根节点的子树。题目所用测试用例保证 queries[i] 不 等于根节点的值。
返回一个长度为 m 的数组 answer ,其中 answer[i] 是执行第 i 个查询后树的高度。
注意:
查询之间是独立的,所以在每个查询执行后,树会回到其 初始 状态。
树的高度是从根到树中某个节点的 最长简单路径中的边数 。
示例 1:
输入:root = [1,3,4,2,null,6,5,null,null,null,null,null,7], queries = [4]
输出:[2]
解释:上图展示了从树中移除以 4 为根节点的子树。
树的高度是 2(路径为 1 -> 3 -> 2)。
示例 2:
输入:root = [5,8,9,2,1,3,7,4,6], queries = [3,2,4,8]
输出:[3,2,3,2]
解释:执行下述查询:

  • 移除以 3 为根节点的子树。树的高度变为 3(路径为 5 -> 8 -> 2 -> 4)。
  • 移除以 2 为根节点的子树。树的高度变为 2(路径为 5 -> 8 -> 1)。
  • 移除以 4 为根节点的子树。树的高度变为 3(路径为 5 -> 8 -> 2 -> 6)。
  • 移除以 8 为根节点的子树。树的高度变为 2(路径为 5 -> 9 -> 3)。
    提示:
    树中节点的数目是 n
    2 <= n <= 105
    1 <= Node.val <= n
    树中的所有值 互不相同
    m == queries.length
    1 <= m <= min(n, 104)
    1 <= queries[i] <= n
    queries[i] != root.val

深度优先搜索(错误)

DFS的参数:TreeNode* root ,int height 。height是当前节点到根节点的最短距离。
DFS的返回值:当前子树的高度。
m_vRet[i] 记录删除值为i的子树后,高度减少多少。
DFS:过程。
记录各子树的高度。
如果没有子树,返回。
令child1是最高的子树,child2是次高的子树。
m_vRet[child1] = child1的高度-child2的高度。
如果child2不存在,可以假定它的高度为-1。
对个查询的值,整棵树的高度-m_vRet[que]
错误原因: 只有删除同层次(leve)节点高度最高的子树时,高度才会发生变化。不是兄弟节点的最高,次高;而是整个层次的最高次高。

深度优先搜索(更正)

DFS的参数:TreeNode* cur,int leve
DFS返回值:m_leve2[cur->value]
DFS:过程
m_leve[cur]记录,cur的层次,根节点是0。
m_leve2[cur]记录,cur子树的层次数量。 叶子节点为1。
分如下几步:
int iHeight = DFS(root,0);
leveToLeve2 记录各层次的leve2
对leveToLeve2[i]按降序排序
计算各查询的sub:
auto& v = leveToLeve2[m_leve[que]];
如果不是当前层次的最大leve2,则sub为0。
如果当前层次只有一个节点,sub = v[0]
否则 sub = v[1]
当前查询的值就是:iHeight-1 - sub。
时间复杂度:O(nlogn) 理论上瓶颈在排序,实际上在DFS。力扣上的DFS非常花时间。

代码

核心代码

#define MaxValue (100'000)
class Solution {
public:vector<int> treeQueries(TreeNode* root, vector<int>& queries) {int iHeight = DFS(root,0);vector<int> leveToLeve2[MaxValue + 1];for (int i = 1; i <= MaxValue; i++) {leveToLeve2[m_leve[i]].emplace_back(m_leve2[i]);}for (int i = 0; i < MaxValue; i++) {sort(leveToLeve2[i].begin(), leveToLeve2[i].end(),greater<>());}vector<int> ret;for (const auto& que : queries) {int sub = 0;auto& v = leveToLeve2[m_leve[que]];if (m_leve2[que] == v[0]) {sub = (1 == v.size()) ? v[0] : (v[0] - v[1]);}ret.emplace_back(iHeight-1 - sub);}return ret;}int DFS(TreeNode* cur,int leve) {if (nullptr == cur) { return 0; }m_leve[cur->val] = leve;const int i1 = DFS(cur->left,leve+1);const int i2 = DFS(cur->right,leve+1);		return m_leve2[cur->val] = max(i1, i2) + 1;}int m_leve[MaxValue + 1] = { 0 };int m_leve2[MaxValue + 1] = { 0 };};

单元测试

template<class T1, class T2>
void AssertEx(const T1& t1, const T2& t2)
{Assert::AreEqual(t1, t2);
}template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{Assert::AreEqual(v1.size(), v2.size());for (int i = 0; i < v1.size(); i++){Assert::AreEqual(v1[i], v2[i]);}
}template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{sort(vv1.begin(), vv1.end());sort(vv2.begin(), vv2.end());Assert::AreEqual(vv1.size(), vv2.size());for (int i = 0; i < vv1.size(); i++){AssertEx(vv1[i], vv2[i]);}
}namespace UnitTest
{vector<int> nums, queries;const int null = 100'000;TEST_CLASS(UnitTest){public:TEST_METHOD(TestMethod00){nums = { 1, 3, 4, 2, null, 6, 5, null, null, null, null, null, 7 }, queries = { 4 };auto root = NTree::Init(nums,null);auto res = Solution().treeQueries(root, queries);AssertEx(vector<int>{2}, res);}TEST_METHOD(TestMethod01){nums = { 5,8,9,2,1,3,7,4,6 }, queries = { 3,2,4,8 };auto root = NTree::Init(nums, null);auto res = Solution().treeQueries(root, queries);AssertEx(vector<int>{3, 2, 3, 2}, res);}};
}

求第k小函数优化

nth_element(a,a+k,a+n);
功能:函数只是把下标为k的元素放在了正确位置,对其它元素并没有排序当然k左边元素都小于等于它,右边元素都大于等于它,所以可以利用这个函数快速定位某个元素。
理论上可以把时间复杂度降到:O(n) 实际上稍稍提高速度。

class Solution {
public:vector<int> treeQueries(TreeNode* root, vector<int>& queries) {int iHeight = DFS(root,0);vector<int> leveToLeve2[MaxValue + 1];for (int i = 1; i <= MaxValue; i++) {leveToLeve2[m_leve[i]].emplace_back(m_leve2[i]);}for (int i = 0; i < MaxValue; i++) {if(leveToLeve2[i].size() >= 2 )nth_element(leveToLeve2[i].begin(), leveToLeve2[i].end()-2,leveToLeve2[i].end());}vector<int> ret;for (const auto& que : queries) {int sub = 0;auto& v = leveToLeve2[m_leve[que]];if (m_leve2[que] == v.back()) {sub = (1 == v.size()) ? v.back() : (v.back() - v[v.size()-2]);}ret.emplace_back(iHeight-1 - sub);}return ret;}int DFS(TreeNode* cur,int leve) {if (nullptr == cur) { return 0; }m_leve[cur->val] = leve;const int i1 = DFS(cur->left,leve+1);const int i2 = DFS(cur->right,leve+1);		return m_leve2[cur->val] = max(i1, i2) + 1;}int m_leve[MaxValue + 1] = { 0 };int m_leve2[MaxValue + 1] = { 0 };};

扩展阅读

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关推荐

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模式Hash和history

vuerouter有两种路由模式Hash和history。区别&#xff1a;Hash为默认模式&#xff0c;url中包含一个#符号的哈希部分。优势&#xff1a;兼容性好&#xff0c;不需要后端服务器的特殊配置。缺点&#xff1a;不够美观&#xff0c;搜索引擎优化较差。History模式使用的浏览器的His…

C# 写入SQLServer数据库报错SqlException: 不能将值 NULL 插入列 ‘ID‘

private int id; [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]//id自增 public int ID { get > id; set > id value; } 将ID属性下的标识规范由否改成是

STM32-寄存器时钟配置指南

目录 启动 SystemInit SetSysClock 总结 启动 从startup_stm32f0xx.s内的开头的Description可以看到 ;* Description : STM32F051 devices vector table for EWARM toolchain. ;* This module performs: ;* - Set the in…

微信小程序支付流程

前端需要做的事情&#xff1a; 生成平台订单&#xff1a;前端调用接口&#xff0c;向后端传递购买的商品信息、收货人信息&#xff0c;&#xff08;后端生成平台订单&#xff0c;返回订单编号&#xff09;获取预付单信息&#xff1a;将订单编号发送给后端后&#xff0c;&#x…

Hadoop单机版环境搭建

一 . 案例信息 Hadoop 的安装部署的模式一共有三种&#xff1a; 本地模式&#xff0c;默认的模式&#xff0c;无需运行任何守护进程&#xff08; daemon &#xff09;&#xff0c;所有程序都在单个 JVM 上执行。由 于在本机模式下测试和调试 MapReduce 程序较为方便&#x…

leetocde662. 二叉树最大宽度,面试必刷题,思路清晰,分点解析,附代码详解带你完全弄懂

leetocde662. 二叉树最大宽度 做此题之前可以先做一下二叉树的层序遍历。具体题目如下&#xff1a; leetcode102二叉树的层序遍历 我也写过题解&#xff0c;可以先看看学习一下&#xff0c;如果会做层序遍历了&#xff0c;那么这题相对来说会简单很多。 具体题目 给你一棵…

[OJ]水位线问题,1.采用回溯法(深度优先遍历求解)2.采用广度优先遍历求解

1.深度优先遍历 使用回溯法,深度优先遍历利用栈先进后出的特点,在加水控制水量失败时, 回到最近一次可对水进行加水与否的位置1.对于给定水量k,是否在[l,r]之间&#xff0c; 是:是否加水(加水y,用掉x,是否在[l,r]之间)(不加水y,用掉x,是否在[l,r]之间)先尝试加水&#xff0c;如…

NVIDIA全面转向开源GPU内核模块

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

FastAPI(七十八)实战开发《在线课程学习系统》接口开发-- 评论

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 梳理下思路 1.判断是否登录 2.课程是否存在 3.如果是回复&#xff0c;查看回复是否存在 4.是否有权限 5.发起评论 首先新增pydantic模型 class Cour…

音视频入门基础:WAV专题(2)——WAV格式简介

注&#xff1a;本文有部分内容引用了维基百科&#xff1a;https://zh.wikipedia.org/wiki/WAV 一、引言 Waveform Audio File Format&#xff08;缩写WAVE或WAV&#xff09;是微软与IBM公司所开发在个人电脑存储音频流的编码格式&#xff0c;在Windows平台的应用软件受到广泛的…

AI/机器学习(计算机视觉/NLP)方向面试复习3

1. Pooling 有哪些方式&#xff1f;pytorch的实现&#xff1f; Pooling可以分成&#xff1a;最大池化&#xff0c;平均池化&#xff0c;全局平均池化&#xff0c;随机池化&#xff0c;空间金字塔池化。 1. 最大池化&#xff08;Max Pooling&#xff09; 最大池化是最常用的池…

union的特性和大小端

一、union在c和c语言中的特性 1.共享内存空间&#xff1a;union的所有成员共享同一块内存空间。意味着在同一时刻&#xff0c;union 只能存储其成员 中的一个值。当你修改了union中的一个成员&#xff0c;那么其它成员的值也会被改变&#xff0c;因为它们实际上都是指向同一块…

JS逆向高级爬虫

JS逆向高级爬虫 JS逆向的目的是通过运行本地JS的文件或者代码,以实现脱离他的网站和浏览器,并且还能拿到和浏览器加密一样的效果。 10.1、编码算法 【1】摘要算法&#xff1a;一切从MD5开始 MD5是一个非常常见的摘要(hash)逻辑. 其特点就是小巧. 速度快. 极难被破解. 所以,…

skywalking docker部署

skywalking-oap # 拉取skywalking-oap镜像 docker pull apache/skywalking-oap-server:9.7.0# 启动容器 docker run --name oap \ -d \ -p 11800:11800 \ -p 12800:12800 \ apache/skywalking-oap-server:9.7.0skywalking-ui # 摘取skywalking-ui镜像 docker pull apache/sky…

大屏使用技巧——如何实现数据分发

当多个组件需共用同一数据源时&#xff0c;为了减少重复请求&#xff0c;需要进行数据分发。那如何实现接一次数据就能让多个组件映射同一数据源中的不同数据字段呢&#xff1f; 实现思路 目标组件的静态数据中添加标记字段&#xff0c;数据过滤器内通过 data 参数获取到对应…

加密micropython写的程序为.mpy的方法

2024年7月26日 用虚拟机安装一个Linux&#xff0c;本例为CentOS7的Linux系统。 1.保证Linux能够连接网络。 2.进入root用户&#xff0c;使用下面的命令行安装gcc编译器&#xff1a; yum install gcc 3.安装完成后&#xff0c;查看gcc是否安装成功&#xff0c;用下面的命令…

家政项目小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;家政人员管理&#xff0c;家政服务管理&#xff0c;咨询信息管理&#xff0c;咨询服务管理&#xff0c;家政预约管理&#xff0c;留言板管理&#xff0c;系统管理 微信端账号功能…

前端开发知识-vue

大括号里边放键值对&#xff0c;即是一个对象。 一、vue可以简化前端javascript的操作。 主要特点是可以实现视图、数据的双向绑定。 使用vue主要分为三个步骤&#xff1a; 1.javascript中引入vue.js 可以src中可以是vue的网址&#xff0c;也可以是本地下载。 2.在javasc…

FastAPI(七十九)实战开发《在线课程学习系统》接口开发-- 加入课程和退出课程

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 加入课程 我们先看下加入课程 1.是否登录 2.课程是否存在 3.是否已经存在 4.添加 首先实现逻辑 def get_student_course(db: Session, course: int…

C++——QT:保姆级教程,从下载到安装到用QT写出第一个程序

登录官网&#xff0c;在官网选择合适的qt版本进行下载 这里选择5.12.9版本 点击exe文件下载&#xff0c;因为服务器在国外&#xff0c;国内不支持&#xff0c;所以可以从我的网盘下载 链接: https://pan.baidu.com/s/1XMILFS1uHTenH3mH_VlPLw 提取码: 1567 --来自百度网盘超级…