代码随想录算法训练营第二十一天|530.二叉搜索树的最小绝对差、 501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先

530.二叉搜索树的最小绝对差 

题目链接/文章讲解: 代码随想录

视频讲解:二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差_哔哩哔哩_bilibili

1.方法1

1.1分析及思路

了解到差值最小的数为,结点左孩子然后一直向右的叶子结点,或者是右孩子一直向左的叶子结点。

对每一个结点都进行这样的判断。所以就用到了递归。

递归三部曲:

1.功能,参数,返回值

功能:判断结点的最小差值

参数:保存最小值的int*地址,以及结点

返回值:没有必要向上层返回值,所以不需要返回值

2.递归终止条件

假设传入一个非空结点,要进行的操作就是,寻找其前后最接近的值。所以只有NULL是才会结束循环。

3.单层递归逻辑

拿到一个结点,要进行寻找其左孩子的最右结点,以及右孩子的最左结点,然后求最小差值。

1.2代码及注释

void LETF(struct TreeNode* root,int* Min) {// 定义一个指向左子树的节点Nodestruct TreeNode* Node = root->left;// 遍历左子树while(Node!=NULL){// 如果Node的右子节点为空,则说明找到了,左孩子的最右侧的叶子结点if(Node->right == NULL)// 更新最小值Minif(*Min > root->val - Node->val)*Min = root->val - Node->val;Node = Node->right;}
}void RIGHT(struct TreeNode* root,int* Min) {// 定义一个指向右子树的节点Nodestruct TreeNode* Node = root->right;// 遍历右子树while(Node!=NULL){// 如果Node的左子节点为空,则说明找到了右孩子的最左侧叶子结点if(Node->left == NULL)// 更新最小值Minif(*Min > Node->val - root->val)*Min = Node->val - root->val;Node = Node->left;}
}void traversal(struct TreeNode* root,int* Min) {// 如果当前节点为空,直接返回if(root == NULL) return;if(root->left != NULL)LETF(root,Min);//寻找左孩子的最右侧叶子结点if(root->right != NULL)RIGHT(root,Min);//寻找右孩子的最左侧结点// 递归遍历左子树traversal(root->left,Min);// 递归遍历右子树traversal(root->right,Min);
}int getMinimumDifference(struct TreeNode* root) {// 初始化最小值为INT_MAXint Min = INT_MAX;// 从根节点开始遍历traversal(root,&Min);// 返回最小值return Min;
}

2.方法2

2.1分析及思路

与98.验证二叉搜索树思路类似,用两个指针进行遍历,这俩个指针的差值是可能成为最小差值的,因为中序遍历是会得到一个递增的数组的。

1.功能、参数、返回值

功能:得到最小的差值

参数:保存最小差值的Min、根节点root、访问过的前一个结点pre

返回值:下一侧递归不需要及时返回信息,所以不需要返回值

2.终止条件

当访问到NULL时说明该树已经访问完毕。所以终止条件为NULL

3.单层递归的逻辑

拿到一个结点root,用root-pre判断差值,然后递归的访问其左子树,右子树

2.2代码及分析

// 定义一个函数用于遍历二叉搜索树
void traversal(struct TreeNode* root, struct TreeNode* *pre, int* Min) {// 如果当前节点为空,直接返回if(root == NULL) return;// 递归遍历左子树traversal(root->left, pre, Min);// 如果前一个节点不为空if(*pre != NULL){// 更新最小差值if(*Min > (root->val - (*pre)->val)){*Min = (root->val - (*pre)->val);}}// 更新前一个节点为当前节点*pre = root;// 递归遍历右子树traversal(root->right, pre, Min);
}// 定义一个函数用于获取二叉搜索树中节点值的最小差值
int getMinimumDifference(struct TreeNode* root) {// 初始化最小差值为最大整数值int Min = INT_MAX;// 初始化前一个节点为空struct TreeNode* pre = NULL;// 调用遍历函数traversal(root, &pre, &Min);// 返回最小差值return Min;
}

501.二叉搜索树中的众数 

代码随想录

视频讲解:不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数_哔哩哔哩_bilibili

1.分析及思路

最直观的想法就是,访问一遍树,把所有的数出现的频率都统计下来,然后再把频率高的数进行返回。

进行优化,对于二叉搜索树而言,中序遍历会得到一个不减的数组,和上一题类似,使用双指针进行频率的统计,如果当前频率等于最大频率,则说明众数有多个,在结果数组的末尾加上它即可。若大于则说明,已经统计的结果全部作废,要重新统计,即再次从数组下标为0的地方存储结果。

运用了中序遍历,所以可以使用递归法,递归三部曲:

1.功能,参数,返回值

功能:统计二叉树中的众数

参数:需要传入一个根节点,所以有struct TreeNode* root

因为是双指针,所以需要一个struct TreeNode** pre,保存上次访问过的结点

最终返回的是一个数组,所以穿进来一个int* result

以及统计数组的大小的int* returnSize

需要当前频率和最大频率做对比,所以有int* MaxCount,int* NowCount。

2.递归终止条件

很明显,遇到空结点时,没办法统计所以终止。

3.单层递归逻辑

遇到一个结点,看上次访问的结点与它是否相等,相等则频率加1。若不想等则说明,此时访问的是新出现的,此时频率设置为1。若该频率与最大频率相等,则把它加入结果数组的末尾。若大于,则说明,结果数组中的众数全部作废,重新统计。

2.代码及注释

void traversal(struct TreeNode* root, struct TreeNode** pre, int* returnSize, int* result, int* MaxCount, int* NowCount) {// 如果当前节点为空,直接返回if(root == NULL) return;// 递归遍历左子树traversal(root->left, pre, returnSize, result, MaxCount, NowCount);// 如果前一个节点为空,则当前节点是第一个节点,NowCount置为1if(*pre == NULL) *NowCount = 1;// 如果前一个节点的值等于当前节点的值,则当前节点是重复节点,NowCount加1else if((*pre)->val == root->val) (*NowCount)++;// 如果前一个节点的值不等于当前节点的值,则当前节点是新节点,NowCount置为1else *NowCount = 1;// 更新pre指针为当前节点*pre = root;// 如果NowCount等于MaxCount,将当前节点的值加入结果数组并增加返回大小if(*NowCount == *MaxCount) result[(*returnSize)++] = root->val;// 如果NowCount大于MaxCount,更新MaxCount为NowCount,重置返回大小为1,将当前节点的值放入结果数组else if(*NowCount > *MaxCount){*MaxCount = *NowCount;*returnSize = 1;result[0] = root->val;}// 递归遍历右子树traversal(root->right, pre, returnSize, result, MaxCount, NowCount);
}int* findMode(struct TreeNode* root, int* returnSize) {// 初始化返回大小为0*returnSize = 0;// 分配结果数组的内存空间int* result = (int*)malloc(sizeof(int)*10001);// 初始化前一个节点指针、最大出现次数、当前出现次数为0struct TreeNode* pre = NULL;int MaxCount = 0;int NowCount = 0;// 调用traversal函数进行遍历traversal(root, &pre, returnSize, result, &MaxCount, &NowCount);// 返回结果数组return result;
}

236. 二叉树的最近公共祖先  

代码随想录

视频讲解:自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先_哔哩哔哩_bilibili

1.分析及思路

很明显,要想知道最近公共祖先结点,就要从该结点左右子树中找到qp两个结点。也就是先访问其左子树,再访问其右子树,也就是使用的是后续遍历。即找到结点后就向父结点返回。

递归三部曲:

1.功能、参数、返回值

功能:返回最近公共祖先

参数:根节点、p、q

返回值:因为需要向父结点返回有没有该结点,所以需要返回值

2.递归终止条件

当传入NULL时,很明显终止。当找到该结点时,也应该终止。

3.单层递归逻辑

遇到结点时,先访问其左子树,在访问其右子树,才能得到该结点是不是有,目标结点。

1.若左子树有目标结点,右子树也有目标结点,则说明它就是最近公共祖先。

2.若右子树有,左子树没有,则说明最近公共祖先在右侧,即返回右侧返回的结点

3.左子树有,右子树没有,则返回左子树返回的值

4.若都没有很明显,返回NULL

2.代码及注释

// 定义一个函数,用于找到两个节点的最近公共祖先
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {// 如果根节点为空,返回空if(root == NULL) return root;// 如果根节点等于其中一个节点,直接返回根节点if(root == q || root == p) return root;// 递归查找左子树中的最近公共祖先struct TreeNode* left = lowestCommonAncestor(root->left,p,q);// 递归查找右子树中的最近公共祖先struct TreeNode* right = lowestCommonAncestor(root->right,p,q);// 如果左右子树都找到了最近公共祖先,则返回根节点if(left != NULL && right != NULL) return root;// 如果左子树找到了最近公共祖先,则返回左子树的最近公共祖先if(left == NULL && right != NULL) return right;// 如果右子树找到了最近公共祖先,则返回右子树的最近公共祖先if(left != NULL && right == NULL) return left;// 如果左右子树都没有找到最近公共祖先,则返回空return NULL;
}

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

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

相关文章

上门服务系统|上门服务小程序|上门服务软件开发

随着移动互联网技术的普及,上门服务小程序系统成为现代企业数字化转型的关键一环。这一系统为消费者提供了更加便捷、高效以及个性化的服务体验,同时也为企业带来了更广阔的商业机会。让我们来看看上门服务小程序系统的优势和功能。 首先,上门…

qt5与qt6的cmake区别

文章目录 使用cmake构建qt项目,坑很多。一是本身就麻烦,二是,确实坑,因为不同的qtcreator版本,选了不同的kits(套件) 生成的CMakeList.txt文件也不一样。 如果可以的话都选择Qt6的相关选项&…

lv19 多态 4

1 虚函数 虚函数&#xff08; 基类指针可指向派生类对象&#xff0c; 动态联编&#xff09; 先看示例&#xff0c;不加virtual&#xff0c;不认对象认指针。 #include <iostream>using namespace std;class A{ public:A(){ }~A(){ }void show(){cout<<"AAA…

尝鲜18倍速大模型Groq和世界第二AI Mistral(Le Chat)

01 尝鲜 中午,一边吃饭,一边尝试一下最新的AI:Groq,它使用了重新设计的LPU,据说比英伟达的GPU快了18倍。 运行了开源的Mixtral-8x7b模型,屏幕上的文字回复几乎是瞬间的,那种速度感,让人心跳加速。 接着,我尝试了来自欧洲的新贵——Mistral AI的Le Chat。 这个三天前…

Day07:基础入门-抓包技术全局协议封包监听网卡模式APP小程序PC应用

目录 非HTTP/HTTPS协议抓包工具 WireShark 科来网络分析系统 WPE封包 思维导图 章节知识点&#xff1a; 应用架构&#xff1a;Web/APP/云应用/三方服务/负载均衡等 安全产品&#xff1a;CDN/WAF/IDS/IPS/蜜罐/防火墙/杀毒等 渗透命令&#xff1a;文件上传下载/端口服务/Sh…

【前端素材】推荐优质在线通用果蔬商城电商网页eStore平台模板(附源码)

一、需求分析 1、系统定义 通用果蔬网站是指专门提供各类果蔬产品展示和销售的在线平台。它将不同种类的新鲜水果、蔬菜、干果、坚果等聚集在一起&#xff0c;为消费者提供方便、快捷的购物渠道。 2、功能需求 通用果蔬网站是指专门提供各类果蔬产品展示和销售的在线平台。…

应用多元统计分析--多元数据的直观表示(R语言)

例1.2 为了研究全国31个省、市、自治区2018年城镇居民生活消费的分布规律&#xff0c;根据调查资料做区域消费类型划分。 指标&#xff1a; 食品x1&#xff1a;人均食品支出(元/人) 衣着x2&#xff1a;人均衣着商品支出(元/人) 居住x3&#xff1a;人均居住支出(元/人) 生活x4…

如何文件批量重命名?

如何文件批量重命名&#xff1f;在日常工作和生活中&#xff0c;我们经常会面临大量文件需要整理和管理的情况。而文件批量重命名这一简单而实用的功能&#xff0c;则成为了我们高效处理文件的利器。通过文件批量重命名功能&#xff0c;我们可以快速、方便地对多个文件进行统一…

javaee教程郑阿奇课后答案,三年经验月薪50k我是怎么做到的

个人背景 如标题所示&#xff0c;我的个人背景非常简单&#xff0c;Java开发经验1年半&#xff0c;学历普通&#xff0c;2本本科毕业&#xff0c;毕业后出来就一直在Crud&#xff0c;在公司每天重复的工作对我的技术提升并没有什么帮助&#xff0c;但小镇出来的我也深知自我努…

ArmSoM Rockchip系列产品 通用教程 之 CAN 使用

CAN 使用 1. CAN 简介 CAN (controller Area Network)&#xff1a;控制器局域网络总线&#xff0c;是一种有效支持分布式控制或实时控制的串行通信网络。 目前世界上绝大多数汽车制造厂商都采用CAN总线来实现汽车内部控制系统之间的数据通信。 RK3568/RK3588的CAN驱动文件&a…

【程序员是如何看待“祖传代码”的?】《代码的遗产:探索程序员眼中的“祖传代码”》

程序员是如何看待“祖传代码”的&#xff1f; 在程序员的世界里&#xff0c;代码不仅仅是构建软件的基石&#xff0c;它们也承载着历史、智慧和技术的演变。在我的编程生涯中&#xff0c;我遇到过许多神奇而独特的“祖传代码”&#xff0c;这些代码如同古老的魔法书&#xff0…

Redis高级应用——海量数据高并发下Reids的分片集群,原理和应用,集群伸缩以及项目配置

目录 引出Reids海量数据&#xff0c;高并发问题认识Redis集群算法搭建Redis分片集群准备实例安装redis启动 创建集群测试 分片集群原理搭建分片集群散列插槽插槽原理小结 认识集群伸缩需求分析创建新的redis实例添加新节点到redis集群转移插槽自动故障转移 SpringBoot配置Redis…