Day24|二叉树 PART08

235. 二叉搜索树的最近公共祖先

与236类似但可以利用二叉搜索树的性质来做
二叉搜索树:左子 小于头 小于右子
(怪怪的 感觉是不是先记住比较好)(而且也没太理解二叉搜索树的规律)
大体思路:从上到下遍历(从头节点开始遍历,那应该是前序遍历)
公共祖先的节点的值应该在p和q的闭区间内,最近公共祖先是从上到下遍历中遇到的第一个符合条件的节点(至于为什么是第一个我也没捋明白)

写了一下没写出来发现我没搞清楚“沿一条边递归”和“沿整棵树递归”的区别:

在二叉树:公共祖先问题 (opens new window)中,如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树。

在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。

很明显这里的情况是“返回值不为空的时候立即返回”,所以是搜索一条边。

701.二叉搜索树中的插入操作

遍历二叉树,其实可以不考虑题目中提示所说的改变树的结构的插入方式,遇到空节点就插入就行。
递归插入,单层递归逻辑:
入参:
root,val
返回值可以为空(?)其实在这里感觉有没有返回值都行,但是没有的话可能无法知道节点到底有没有插入从而终止递归,有返回值的话返回的节点赋值给?

可以有,也可以没有,但递归函数如果没有返回值的话,实现是比较麻烦的,下面也会给出其具体实现代码。
有返回值的话,可以利用返回值完成新加入的节点与其父节点的赋值操作。

与当前节点比较,大于就往节点右侧插,小于就往节点左侧插

确定终止条件:
当前节点为null说明可以插入

因此可以根据终止条件得知,返回的当前节点由上一次接住:
用java写了一版:

class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {if (root == null) {return new TreeNode(val);}if (root.val > val) {root.left = insertIntoBST(root.left, val);} else {root.right = insertIntoBST(root.right, val);}return root;}
}

450.删除二叉搜索树中的节点

也可以沿着边搜索,遇到删除的节点分三种情况判断:

1.叶子节点,直接返回null
2.左子右子只有一个存在:返回存在的子节点
3.左右子都存在:右子接到该节点的位置,左子接到右子树上最左的叶子节点下,返回右节点

既然有返回值,那么递归的过程中就需要接住这个返回值。

接住的逻辑:

这里相当于把新的节点返回给上一层,上一层就要用 root->left 或者 root->right接住,代码如下:

if (root->val > key) root->left = deleteNode(root->left, key);
if (root->val < key) root->right = deleteNode(root->right, key);
return root;

开写:

class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {if (root == nullptr)return root;if (root->val == key) {if (root->left == nullptr && root->right == nullptr) {return nullptr;} else if (root->left == nullptr || root->right == nullptr) {return root->left == nullptr ? root->right : root->left;} else {findLeaf(root->right)->left = root->left;return root->right;}}if (root->left)root->left = deleteNode(root->left, key);if (root->right)root->right = deleteNode(root->right, key);return root;}TreeNode* findLeaf(TreeNode* root) {while (root->left != nullptr) {root = root->left;}return root;}
};

AC了 上面黑体的部分算是解本题的关键点,可以记住。

669. 修剪二叉搜索树

如果找到不在范围内的节点,
小于最小值,说明该节点及其左子树都不要了
大于最大值,说明该节点及其右子树都不要了

递归逻辑:
记住递归是需要找到本层逻辑,不需要考虑整个递归的套路

本层逻辑:

先判断当前节点,
小于范围:对该节点进行一次删除操作,把节点当作没有左子树的情况返回右节点
大于范围:当作没有右子树的情况返回左节点
再执行删除节点的接住逻辑

开写的时候发现了一个忽略掉的逻辑:
就是把左或右子树接到当前节点上的时候,会忽略对新接入节点的判断:

比如
比如这种情况

比如这种情况,如果low=3, 删除了0后直接接上的2其实也不在范围内

又绕进去了。。用这个逻辑好像不太对

class Solution {
public:TreeNode* trimBST(TreeNode* root, int low, int high) {if (root == nullptr)return root;if (root->val < low) {return root->right;} else if (root->val > high) {return root->left;}if (root->left)root->left = trimBST(root->left, low, high);if (root->right)root->right = trimBST(root->right, low, high);return root;}
};

写了一下果然不对,卡在这个用例了:
跟预想的错误一样

看了一下题解,其实单层递归的逻辑跟这个很类似:

确定单层递归的逻辑
如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。

也就是说其实不能直接返回整个右子树,需要返回右子树中符合条件的头节点

那么如何找到右子树中符合条件的头节点?使用本递归函数进行修剪!
在单层递归中调用递归函数的时候,其实不用考虑递归的整个过程,直接把这个递归函数当作一个实现功能的工具即可!

就是说:

if (root->val < low) {
TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点
return right;
}

开写!

class Solution {
public:TreeNode* trimBST(TreeNode* root, int low, int high) {if (root == nullptr)return root;if (root->val < low) {return trimBST(root->right, low, high);} else if (root->val > high) {return trimBST(root->left, low, high);}if (root->left) {root->left = trimBST(root->left, low, high);}if (root->right) {root->right = trimBST(root->right, low, high);}return root;}
};

其实只需要在第一版代码的基础上稍微修改“返回左右子树中符合条件的 节点” 即可。

108.将有序数组转换为二叉搜索树

做这道题目之前大家可以了解一下这几道:

106.从中序与后序遍历序列构造二叉树 (opens new window)
654.最大二叉树 (opens new window)中其实已经讲过了,如果根据数组构造一棵二叉树。
701.二叉搜索树中的插入操作 (opens new window)
450.删除二叉搜索树中的节点

一开始被卡住了,卡住的点在于看到题干给出的两个例子:
题干给出的例子

一直在想为什么不能说是0左右直接长出长长的两撇(这不算平衡二叉树吗,为什么非要调换-10和-3的位置把-3放在-10的右子)

(查了一下好像本来就可以产生很多答案,姑且把我的构建结果当作正确的一种)

单层递归思路:

入参感觉可以有数组,当前头节点,int left, int right

这里注意:

再来看参数,首先是传入数组,然后就是左下标left和右下标right,我们在二叉树:构造二叉树登场! (opens new window)中提过,在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下标来操作原数组。

首先找到本层传入数组的中点
赋给一个构造出的节点,
该节点的左右节点,根据traversal函数获得

返回该节点

递归终止条件

这里定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点了。

开写

class Solution {
public:TreeNode* sortedArrayToBST(vector<int>& nums) {return traversal(nums, 0, nums.size()-1);}TreeNode* traversal(vector<int>& nums, int left, int right){if(left > right) return nullptr;int mid = left + ((right - left)>>1);TreeNode* root = new TreeNode(nums[mid]);root->left = traversal(nums, left,mid-1);root->right = traversal(nums, mid+1, right);return root;}
};

538.把二叉搜索树转换为累加树

本题与1038题相同

需要写出一个求和的封装,然后遍历该二叉树根据求和替换每个节点的值。
求和就是求出右子树的和 再加 当前节点值

求和过程的递归就是正常遍历就行,给出当前节点的右子树的头节点,遍历一圈获取和(理论上是怎么遍历都可以)

写了一下发现不太对。。没法对应上这个图
不对

圈起来的部分全没法使用上述方法替换val(节点5甚至没有右子树)

感觉也可以将二叉树转换成数组,不过这样可以获取但替换不太方便

还是考虑在遍历过程中按顺序求值并替换,可以按右-〉头-〉左的顺序遍历并替换
每遍历一个节点就把当前值+=sum

class Solution {
public:int sum = 0;TreeNode* convertBST(TreeNode* root) {sum=0;traversal(root);return root;}void traversal(TreeNode* root) {if (root == nullptr)return;if (root->right != nullptr){traversal(root->right);}root->val += sum;sum = root->val;if (root->left != nullptr)traversal(root->left);return;}};

改用java写一写。。:

class Solution {private int sum = 0;public TreeNode convertBST(TreeNode root) {getSum(root);return root;}public void getSum(TreeNode root){if(root==null) return;getSum(root.right);root.val += sum;sum=root.val;getSum(root.left);}
}

最后部分是对二叉树模块总结:

二叉树模块挺全面的,卡哥每题都给出了递归和迭代的解法,但我这次一刷基本上只选择了递归的方法(除了有些层序遍历会用迭代)
而且二叉树这个模块我中间间隔了很久才重新开始刷。。中间经历了找实习+写毕设+回国实习。。实习从C++转到Java。。真的隔了很久。。前面一些二叉树的题(二叉树属性,修改与改造部分)急需二刷

就先这样,一刷二叉树over!!

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

html 解决tooltip宽度显示和文本任意位置换行文本显示问题

.el-tooltip__popper {max-width: 480px;white-space: break-spaces; /* 尝试不同的white-space属性值 */word-break:break-all; }

干货:three.js中的六大光源的知识点。

我们在二维屏幕中感知三维场景的一个最重要的要素就是光&#xff0c;光和光源是three.js中一个非常重要的知识点。本文想借着这个话题&#xff0c;为老铁们分享以下六大光源知识点&#xff1a;环境光、点光源、聚光灯、方向光、半球光、平面光。 一、点光源 在 Three.js 中&a…

模拟string(四)详解

目录 判断string大小关系bool operator(const string&s1,const string s2)代码 bool operator<(const string& s1, const string& s2)代码 bool operator<(const string& s1, const string& s2)代码 bool operator>(const string& s1, const …

Stable Diffusion WebUI本地环境搭建

一、项目代码下载 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui 二、环境配置 conda create --n stafu python3.10.6 实际上跟自己创建的环境没有关系&#xff0c;项目启动会自动复制这个环境&#xff0c;之后项目根据这个基础环境构建 也可以在自己…

机器学习——第一章 绪论

目录 1. 1 引言 1. 2 基本术语 1.3 假设空间 1.4 归纳偏好 1. 1 引言 机器学习致力于研究如何通过计算的手段&#xff0c;利用经验来玫善系统自身的性能在计算机系统中&#xff0c;"经验"通常以"数据"形式存在&#xff0c;因此&#xff0c;机器学习所研…

由字节对齐引发的一场“血案“

最近在搞个网络通信协议&#xff0c; 采用socket udp传输&#xff0c; 运行时&#xff0c;居然报段错误了&#xff0c; 经过debug&#xff0c;发现居然是因为字节对齐问题导致的。 这个问题在实现通信协议&#xff0c;是经常会遇到的问题&#xff0c; 为了方便读者理解&am…

PSVR2下个月将正式支持PC

PlayStation VR 2将于下个月正式支持PC平台。连接PC&#xff0c;需要使用PlayStation VR2头显PC适配器&#xff0c;该适配器将于8月7日发售。 需要注意的是&#xff0c;玩家还需要一根兼容DisplayPort 1.4的线缆、一个Steam账号以及满足最低配置要求的PC。 索尼特别强调&#…

js 替换json中的转义字符 \

例如有以下字符串 "\"{\\\"account\\\":\\\"66\\\",\\\"name\\\":\\\"66\\\"}\"" 想得到如下字符串 {"account":"66","name":"66"} 执行替换字符串 "\"{…

大坝安全监测设备有哪些主要功能?

推荐型号&#xff1a;TH-WY1】大坝安全监测设备的主要功能包括以下几个方面&#xff1a; 1. **实时监测大坝的各项物理参数**&#xff1a;包括应变、位移、水位、流量等<sup>1</sup><sup>2</sup>。 2. **数据处理和分析**&#xff1a;对监测数据进行处…

热门音效、BGM哪里可以免费下载?

剪辑的奇妙世界等你探索&#xff01;在这个创意的领域里&#xff0c;音效是创造氛围、增强表现力的重要元素。我整理了8个优质的剪辑音效素材网站&#xff0c;它们提供了丰富多样的音效资源&#xff0c;无论是制作视频、音乐还是动画&#xff0c;都能为你提供所需的声音。 1、b…

单关节电机动力学辨识

这是一个单关节电机的动力学辨识过程&#xff0c;这是一个yaw轴转动电机的动力学辨识过程 1、动力学建模 &#xff08;1&#xff09;整体动力学 F J α f F J\alpha f FJαf 单关节的物理量包括惯性项、离心力和科氏力、摩擦力。这里忽略离心力和科氏力&#xff0c;据说…

信息学奥赛初赛天天练-47-CSP-J2020完善程序1-质数、因数、质因数、质因数分解算法、质因数分解算法优化

PDF文档公众号回复关键字:20240727 2020 CSP-J 完善程序1 1 完善程序 (单选题 &#xff0c;每小题3分&#xff0c;共30分) 质因数分解给出正整数 n&#xff0c;请输出将 n 质因数分解的结果&#xff0c;结果从小到大输出 例如&#xff1a;输入 n120&#xff0c;程序应该输出…

mysql报错:Unknown collation: ‘utf8mb4_0900_ai_ci‘的原因及解决方法

参考博客&#xff1a;http://t.csdnimg.cn/NRzyk 报错场景描述 使用navicate在查询中运行sql语句时报错&#xff1a;Unknown collation: utf8mb4_0900_ai_ci 报错原因 生成转储文件的数据库版本为8.0&#xff0c;我本地数据库版本为5.6&#xff0c;高版本导入到低版本&…

【C++】透析类和对象(下)

有不懂的可以翻阅我之前文章&#xff01; 个人主页&#xff1a;CSDN_小八哥向前冲 所属专栏&#xff1a;CSDN_C入门 目录 拷贝构造函数 运算符重载 赋值运算符重载 取地址运算符重载 const成员函数 取地址重载 再探构造函数 初始化列表 类型转换 static成员 友元 内…

【CN】Argo 持续集成和交付(一)

1.简介 Argo 英 [ˈɑ:ɡəu] 美 [ˈɑrˌɡo] Kubernetes 原生工具&#xff0c;用于运行工作流程、管理集群以及正确执行 GitOps。 Argo 于 2020 年 3 月 26 日被 CNCF 接受为孵化成熟度级别&#xff0c;然后于 2022 年 12 月 6 日转移到毕业成熟度级别。 argoproj.github.i…

(最全最小白易懂版)Yolov8新手教程-配置环境、数据集处理、目标检测、结果分析处理(图像指标、可视化结果)、报错分析等全过程学习记录

目录 一、安装环境&#xff08;配置yolo、demo测试&#xff09; 二、数据集准备&#xff08;格式学习&#xff09; 三、训练数据集 1.划分数据集 2.训练数据集 2.1常规训练 2.2微调 3.各种报错记录 3.1AttributeError 3.2TypeError 3.3Error while loading conda en…

Flutter Dio网络请求报错FormatException: Unexpected character

最近开发Flutter项目&#xff0c;网络请求采用的是Dio框架&#xff0c;在发起网络请求的时候报错&#xff1a; 网络请求返回的数据为&#xff1a; var returnCitySN {\"cip\": \"127.0.0.1\", \"cid\": \"00\", \"cname\"…

浅谈 JVM 的内存划分、类加载、垃圾回收机制

文章目录 一、JVM内存划分1.1、JVM为什么要进行内存划分&#xff1f; 二、JVM类加载2.1、什么是类加载&#xff1f;2.2、类加载大体过程2.3、何时触发类加载&#xff1f;2.4、双亲委派模型[!面试高频问题]2.4.1、类加载器2.4.1、什么是双亲委派模型&#xff1f; 三、JVM 垃圾回…

Flink SQL 的工作机制

前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出&#xff0c;一段查询 SQL / 使用TableAPI 编写的程序&#xff08;以下简称 TableAPI 代码&#xff09;从输入到编译为可执行的 JobGraph 主要经历如下几个阶段&#xff1a; 将 SQL文本 / TableAPI 代码转化为逻辑执…

书生大模型实战营--L1关卡-OpenCompass 评测 InternLM-1.8B 实践

一、使用 OpenCompass 评测 internlm2-chat-1.8b 模型在 MMLU 数据集上的性能 1、使用lmdeploy部署 internlm2-chat-1.8b模型 2、根据OpenCompass官网教程安装并下载数据集 opencompass/README_zh-CN.md at main open-compass/opencompass GitHub 注意&#xff1a; pyhton…