代码随想录算法训练营第60期第二十天打卡

        大家好,今天我们继续进入二叉树的章节,二叉树章节应该已经过半了,大家再坚持一下,那么废话不多说,我们继续今天的内容。

第一题对应力扣编号为235的二叉搜索树的最近公共祖先

        其实我们上次任务就接触过了二叉树的最近公共祖先,其实很难,我们很容易就迷糊我们究竟如何返回以及什么情况下才会有最近公共祖先,其实最近的公共祖先就是两个节点分别处在最近的左右子树中,两边均返回true这种情况下我们就找到了最近公共祖先,那我们知道二叉搜索树是一种特殊的二叉树,那么它的最近公共祖先应该如何找呢?我们一起走进我们今天的第一题:

      其实这跟我们上次的二叉树的最近公共祖先是一样的要求,我们原来的思路是自底向上回溯,遇到一个节点的左子树里有p,右子树里有q,那么当前节点就是最近公共祖先。很明显我们应该好好利用二叉搜索树的特点来助力我们解决这道题目,因为是有序树,所以 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。我们可以利用这个二叉搜索树的性质,但是我们会思考我们这样找到的节点究竟是不是最近的公共祖先,我给出大家一个代码随想录上的例子:

       其实我们可以看到p,q的最近公共祖先是5,通过图我们可以看到如何我们从5向左遍历我们将会失去成为p的祖先的可能,同理如果我们向右遍历我们将会失去成为q的祖先的可能,所以当我们从上向下去递归遍历,第一次遇到 cur节点是数值在[q, p]区间中,那么cur就是 q和p的最近公共祖先。因此我们可以得到如果我们从上往下遍历如果我们第一次遇到 cur节点是数值在[q, p]区间中,那么cur就是 q和p的最近公共祖先。那我们就尝试写一下递归代码,首先大家要明白单层递归的逻辑,如果我当前节点的值比p,q两个节点的值都要小的话说明我们要寻找的目标应该是右边,我们应该向右遍历,相反如果我当前节点的值比p,q两个节点的值都要大的话说明我们要寻找的目标应该是左边,我们应该向左遍历,因此这个二叉搜索树由于有顺序我们从上往下递归也是可以实现的,我们尝试写一下代码:

class Solution {
private:TreeNode* traversal(TreeNode *cur, TreeNode* p, TreeNode *q){if (cur == NULL) return NULL;//这时候我们的搜索目标应该是在左边if (cur -> val > p -> val && cur -> val > q -> val){TreeNode* left = traversal(cur -> left, p, q);if (left != NULL) return left;}if (cur -> val < p -> val && cur -> val < q -> val){TreeNode* right = traversal(cur -> right, p, q);if (right != NULL) return right;}return cur;//如果一边大一边小就说明这就是最近公共祖先了}
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {return traversal(root, p, q);}
};

       这个代码只要大家理解了我上面的思路就不难了,还是二叉搜索树的特殊性质很重要。我们这道题就讲解到这里,接下来我们进入下一道题目。

第二题对应力扣编号为701的题目二叉搜索树中的插入操作

       我们来到了今天的第二题,这个是关于二叉搜索树的插入操作,我们直接看到题目的具体要求:

        要解决这道题目我感觉我们要明白的是我们应该考虑往左边插还是往右边插,这个其实我们还是得考虑二叉搜索树的性质,那我们应该如何考虑呢?其实题目不算难,我们返回有效的结果就可以,也就是我们找到适合的插入位置并且这个地方是空节点我们就可以插入,那其实我们还是递归的过程,首先有一种特殊的情况如果我们的根节点是空节点我们就直接把题目中给出的节点插入到空节点就可以了,大家一起来看一看我们的递归代码:

class Solution {
public:TreeNode* insertIntoBST(TreeNode* root, int val) {if (root == NULL){TreeNode *node = new TreeNode(val);return node;}if (root -> val > val){root -> left = insertIntoBST(root -> left, val);}else if (root -> val < val){root -> right = insertIntoBST(root -> right, val);}else return root;return root;}
};

        我们还是搞明白我们插入的逻辑,首先就是空节点的话我们就直接插入到空节点就可以,如果我给出的值比根节点小,就说明我当前的值应该往左边插入,如果我给出的值比根节点大,就说明我当前的值应该往右边插入,如果相等我也无需插入了直接返回根节点了,根节点就可以取代我这个节点,这样这个题目我们就解决了,相信大家可以明白,这道题难度不大,我们要进入下一道题目了。

第三题对应力扣编号为450的题目删除二叉树中的节点

       其实这跟上一道题目不就是异曲同工吗?上一题我们需要插入,这一题我们删除,我们就直接进入这道题目:

         首先还是我们得找到这个节点否则我们删什么呢?还是递归对吧,我们要找到要删除的节点,这里有一个地方很难,就是我调整二叉树的时候不好理解,我要分的几种情况我都在代码注释里给大家写清楚了:

class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {if (root == nullptr) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了if (root->val == key) {// 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点if (root->left == nullptr && root->right == nullptr) {///! 内存释放delete root;return nullptr;}// 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点else if (root->left == nullptr) {auto retNode = root->right;///! 内存释放delete root;return retNode;}// 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点else if (root->right == nullptr) {auto retNode = root->left;///! 内存释放delete root;return retNode;}// 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置// 并返回删除节点右孩子为新的根节点。else {TreeNode* cur = root->right; // 找右子树最左面的节点while(cur->left != nullptr) {cur = cur->left;}cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置TreeNode* tmp = root;   // 把root节点保存一下,下面来删除root = root->right;     // 返回旧root的右孩子作为新rootdelete tmp;             // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)return root;}}if (root->val > key) root->left = deleteNode(root->left, key);if (root->val < key) root->right = deleteNode(root->right, key);return root;}
};

      我重点讲解最后的else的情况,就是左右子树都不为空的时候我们删除了节点我们应该如何调整这棵搜索二叉树,这个相当难,我们举个例子来理解一下:

       比方说这棵二叉树,我们要删除7这个节点的话我们不得不让其左孩子或者右孩子继位,但是我们知道二叉搜索树的话节点7它的左子树的值都是小于7的,右子树的值都是大于7的,我们让7的右孩子继位,如果7没了我们的左子树就要去寻找新的父节点,我们选择的是比7大一点的节点就是了,因此这个位置我们就找到了右子树的最左边的位置,这样才可以保证我们将7删除之后我所组成的二叉树还是一棵二叉搜索树,这就是本道题目最难想的地方,那我们也看一下它的代码实现,代码里前面的几种情况都是很简单的,上面代码的注释我也清晰标注了,关键看这种情况,首先拿到右孩子,让右孩子继承父节点的位置,接下来我们要安顿好原先父节点的左子树,我们选择的是右子树的最左边的位置,我们借助一个变量来保存父节点,然后我们将右孩子赋值给根节点,最后返回根节点就可以了,最后大家还要注意递归,什么情况下往左递归,什么情况下往右递归,这道题我就先给大家解释道这里。

总结

         今天的二叉搜索树的最近公共祖先其实不难,比普通的要简单一些,因为它有独特的性质,二叉搜索树插入节点简单的原因是我们不需要改变二叉搜索树的结构,删除就难在我们要去改变二叉搜索树的结构,

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

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

相关文章

8.0 西门子PLC的S7通讯解析

PC与西门子PLC的S7通讯主要有如下几个步骤: 1. TCP的三次握手(由Socket对象自动完成) 2.发送访问请求:COTP 3. 交换通讯信息:setup Commnunication 一、发送访问请求:COTP 比如向PLC请求+以及PLC返回响应的一个实际例子如下: 发送PLC:----> 03 00 00 16 11 E0 …

Nacos-SpringBoot 配置无法自动刷新问题排查

背景 Nacos SpringBoot版本中&#xff0c;提供了NacosValue注解&#xff0c;支持控制台修改值时&#xff0c;自动刷新&#xff0c;但是今天遇见了无法自动刷新的问题。 环境 SpringBoot 2.2.x nacos-client&#xff1a;2.1.0 nacos-config-spring-boot-starter&#xff1a;0…

JAVA | 聚焦 OutOfMemoryError 异常

个人主页 文章专栏 在正文开始前&#xff0c;我想多说几句&#xff0c;也就是吐苦水吧…最近这段时间一直想写点东西&#xff0c;停下来反思思考一下。 心中万言&#xff0c;真正执笔时又不知先写些什么。通常这个时候&#xff0c;我都会随便写写&#xff0c;文风极像散文&…

基于开源技术体系的品牌赛道力重构:AI智能名片与S2B2C商城小程序源码驱动的品类创新机制研究

摘要&#xff1a;在数字经济与实体经济深度融合的背景下&#xff0c;品牌竞争已从单一产品力竞争转向生态化、技术化的赛道力竞争。本文以开源AI大模型、AI智能名片及S2B2C商城小程序源码为核心技术载体&#xff0c;构建"技术赋能-场景贯通-生态协同"三维分析框架&am…

【vue3】购物车实战:从状态管理到用户体验的全流程实现

在电商项目中&#xff0c;购物车是核心功能之一&#xff0c;需要兼顾数据一致性、用户体验和逻辑复杂度。 本文结合 Vue3 Pinia 技术栈&#xff0c;详细讲解如何实现一个高效且易用的购物车系统&#xff0c;重点剖析 添加购物车 和 头部购物车预览 的核心逻辑与实现细节。 一…

卡洛诗西餐厅,以“中式西餐”为核心战略

在餐饮市场的激烈竞争中&#xff0c;“本土化”是许多国际餐饮品牌难以跨越的鸿沟——要么因水土不服黯然退场&#xff0c;要么因过度妥协失去特色。然而&#xff0c;卡洛诗以“中式西餐”为核心战略&#xff0c;将西餐与国内饮食文化深度融合&#xff0c;不仅破解了西餐本土化…

28-29【动手学深度学习】批量归一化 + ResNet

1. 批量归一化 1.1 原理 当神经网络比较深的时候会发现&#xff1a;数据在下面&#xff0c;损失函数在上面&#xff0c;这样会出现什么问题&#xff1f; 正向传递的时候&#xff0c;数据是从下往上一步一步往上传递反向传递的时候&#xff0c;数据是从上面往下传递&#xff0…

【Linux网络】Http服务优化 - 增加请求后缀、状态码描述、重定向、自动跳转及注册多功能服务

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…

AIGC(生成式AI)试用 32 -- AI做软件程序测试 3

总结之前的AI做程序测试过程&#xff0c;试图优化提问方式&#xff0c;整合完成的AI程序测试提问&#xff0c;探索更多可能的AI测试 AIGC&#xff08;生成式AI&#xff09;试用 30 -- AI做软件程序测试 1 AIGC&#xff08;生成式AI&#xff09;试用 31 -- AI做软件程序…

C语言实现迪杰斯特拉算法进行路径规划

使用C语言实现迪杰斯特拉算法进行路径规划 迪杰斯特拉算法是一种用于寻找加权图中最短路径的经典算法。它特别适合用于计算从一个起点到其他所有节点的最短路径&#xff0c;前提是图中的边权重为非负数。 一、迪杰斯特拉算法的基本原理 迪杰斯特拉算法的核心思想是“贪心法”…

引领印尼 Web3 变革:Mandala Chain 如何助力 1 亿用户迈向数字未来?

当前 Web3 的发展正处于关键转折点&#xff0c;行业亟需吸引新用户以推动 Web3 的真正大规模采用。然而&#xff0c;大规模采用面临着核心挑战&#xff1a;数据泄露风险、集中存储的安全漏洞、跨系统互操作性障碍&#xff0c;以及低效的服务访问等问题。如何才能真正突破这些瓶…

WebSocket是h5定义的,双向通信,节省资源,更好的及时通信

浏览器和服务器之间的通信更便利&#xff0c;比http的轮询等效率提高很多&#xff0c; WebSocket并不是权限的协议&#xff0c;而是利用http协议来建立连接 websocket必须由浏览器发起请求&#xff0c;协议是一个标准的http请求&#xff0c;格式如下 GET ws://example.com:3…

Kaamel白皮书:IoT设备安全隐私评估实践

1. IoT安全与隐私领域的现状与挑战 随着物联网技术的快速发展&#xff0c;IoT设备在全球范围内呈现爆发式增长。然而&#xff0c;IoT设备带来便捷的同时&#xff0c;也引发了严峻的安全与隐私问题。根据NSF&#xff08;美国国家科学基金会&#xff09;的研究表明&#xff0c;I…

php安装swoole扩展

PHP安装swoole扩展 Swoole官网 安装准备 安装前必须保证系统已经安装了下列软件 4.8 版本需要 PHP-7.2 或更高版本5.0 版本需要 PHP-8.0 或更高版本6.0 版本需要 PHP-8.1 或更高版本gcc-4.8 或更高版本makeautoconf 安装Swool扩展 安装官方文档安装后需要再php.ini中增加…

服务器传输数据存储数据建议 传输慢的原因

一、JSON存储的局限性 1. 性能瓶颈 全量读写&#xff1a;JSON文件通常需要整体加载到内存中才能操作&#xff0c;当数据量大时&#xff08;如几百MB&#xff09;&#xff0c;I/O延迟和内存占用会显著增加。 无索引机制&#xff1a;查找数据需要遍历所有条目&#xff08;时间复…

Android四大核心组件

目录 一、为什么需要四大组件&#xff1f; 二、Activity&#xff1a;看得见的界面 核心功能 生命周期图解 代码示例 三、Service&#xff1a;看不见的劳动者 两大类型 生命周期对比 注意陷阱 四、BroadcastReceiver&#xff1a;消息传递专员 两种注册方式 广播类型 …

「Mac畅玩AIGC与多模态01」架构篇01 - 展示层到硬件层的架构总览

一、概述 AIGC&#xff08;AI Generated Content&#xff09;系统由多个结构层级组成&#xff0c;自上而下涵盖交互界面、API 通信、模型推理、计算框架、底层驱动与硬件支持。本篇梳理 AIGC 应用的六层体系结构&#xff0c;明确各组件在系统中的职责与上下游关系&#xff0c;…

[MERN 项目实战] MERN Multi-Vendor 电商平台开发笔记(v2.0 从 bug 到结构优化的工程记录)

[MERN 项目实战] MERN Multi-Vendor 电商平台开发笔记&#xff08;v2.0 从 bug 到结构优化的工程记录&#xff09; 其实之前没想着这么快就能把 2.0 的笔记写出来的&#xff0c;之前的预期是&#xff0c;下一个阶段会一直维持到将 MERN 项目写完&#xff0c;毕竟后期很多东西都…

互斥量函数组

头文件 #include <pthread.h> pthread_mutex_init 函数原型&#xff1a; int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 函数参数&#xff1a; mutex&#xff1a;指向要初始化的互斥量的指针。 attr&#xf…

互联网的下一代脉搏:深入理解 QUIC 协议

互联网的下一代脉搏&#xff1a;深入理解 QUIC 协议 互联网是现代社会的基石&#xff0c;而数据在其中高效、安全地传输是其运转的关键。长期以来&#xff0c;传输层的 TCP&#xff08;传输控制协议&#xff09;一直是互联网的主力军。然而&#xff0c;随着互联网应用场景的日…