代码随想录算法训练营day18
代码随想录算法训练营
—day18
文章目录
- 代码随想录算法训练营
- 前言
- 一、530.二叉搜索树的最小绝对差
- 递归法
- 迭代法
- 二、501.二叉搜索树中的众数
- 普通二叉树的方法
- 递归法
- 中序迭代法
- 三、 236. 二叉树的最近公共祖先
- 递归法
- 总结
前言
今天是算法营的第18天,希望自己能够坚持下来!
今日任务:
● 530.二叉搜索树的最小绝对差
● 501. 二叉搜索树中的众数
● 236. 二叉树的最近公共祖先
一、530.二叉搜索树的最小绝对差
题目链接
文章讲解
视频讲解
思路:
二叉搜索树的特点,中序遍历得出递增的数组。
因此最小绝对差就会出现在相邻的两个元素之间。
使用双指针的方法,一前一后指向树的两个节点,记录最小绝对差。
递归法
- 递归函数的参数和返回值:参数:当前传入节点。 返回值:用一个全局变量存储最小绝对差,所以不需要返回值。
- 终止条件:遇到空节点了为终止。
- 单层递归的逻辑:递归左节点;计算当前节点和上一个节点的差,记录最小值;递归右节点
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int result = INT_MAX;TreeNode* pre = nullptr; //指向上一个节点//使用双指针和中序遍历,计算相邻的两个节点的差,记录最小值void traversal(TreeNode* cur) {if (cur == nullptr) return;traversal(cur->left);//左if (pre != nullptr) result = min(result, cur->val - pre->val); //中pre = cur;//更新pre指针traversal(cur->right);//右return;}int getMinimumDifference(TreeNode* root) {traversal(root);return result;}
};
迭代法
使用中序迭代法模板也可以做。
代码如下:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int getMinimumDifference(TreeNode* root) {int result = INT_MAX;TreeNode* pre = nullptr;stack<TreeNode*> st;TreeNode* cur = root;while (cur != nullptr || !st.empty()) {if (cur != nullptr) { // 指针来访问节点,访问到最底层st.push(cur); // 将访问的节点放进栈cur = cur->left; //左} else {cur = st.top();st.pop();if (pre != nullptr) { //中result = min(result, cur->val - pre->val);}pre = cur;cur = cur->right; //右}}return result;}
};
二、501.二叉搜索树中的众数
题目链接
文章讲解
视频讲解
普通二叉树的方法
思路:
- 遍历二叉树,将每个元素和出现的次数记录在map中
- 将map转成vector,定义一个cmp函数,将vector用sort按降序排序
- 取vector的第一个元素,然后遍历vector看是否还有出现频率相同的其他元素。
代码如下:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
private:void searchBST(TreeNode* cur, unordered_map<int,int>& map) {if (cur == nullptr) return;map[cur->val]++;searchBST(cur->left, map);searchBST(cur->right, map);}//这里定义成static调用的时候就不需要对象bool static cmp (const pair<int,int>& a, const pair<int,int>& b) { return a.second > b.second;}public:vector<int> findMode(TreeNode* root) {unordered_map<int, int> map;vector<int> result;if (root == nullptr) return result;searchBST(root, map); //遍历二叉树将元素出现频率保存在map中vector<pair<int,int>> vec(map.begin(), map.end()); //将map转成vector来排序sort(vec.begin(), vec.end(), cmp); //排序,a>b返回true,a在前面,降序result.push_back(vec[0].first);for (int i = 1; i < vec.size(); i++) {if (vec[i].second == vec[0].second) result.push_back(vec[i].first);else break;}return result;}
};
递归法
跟上一题计算最小绝对差一样,可以使用双指针的方法,因为是二叉搜索树,按照中序遍历,相同节点值只会是相邻的节点。
- 递归函数的参数和返回值:参数:当前传入节点。 返回值:用一个全局变量存储结果集,所以不需要返回值。
- 终止条件:遇到空节点了为终止。
- 单层递归的逻辑:递归左节点;
·用count变量统计当前遍历元素的频率,用MaxCount保存最大频率,
·如果当前节点是第一个节点,count=1,如果pre = cur,count++,
·如果pre !=cur,说明是新的元素,重新从1开始计数,count=1;
·并且通过比较count和MaxCount的大小,实时更新结果集,
· 当MaxCount更新之后,需要对根据旧MaxCount保存下来的结果集清空,重新放入新的元素;
·递归右节点
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int MaxCount = 0; //最大频率int count = 0; //统计频率vector<int> result;TreeNode* pre = nullptr;void traversal(TreeNode* cur) {if (cur == nullptr) return;traversal(cur->left); //左//中if (pre == nullptr) count = 1; //第一个节点else if (pre->val == cur->val) count++; //上一个节点跟当前节点相同else count = 1; //上一个节点跟当前节点不相同pre = cur; //更新上一个节点if (count == MaxCount) result.push_back(cur->val); //如果和最大值相等,放入结果集if (count > MaxCount) { //当目前元素出现的次数比最大值高,清空之前的结果集,把当前元素放入结果集MaxCount = count; //更新最大频率result.clear();result.push_back(cur->val);}traversal(cur->right); //右}vector<int> findMode(TreeNode* root) {if (root == nullptr) return result;traversal(root);return result;}
};
中序迭代法
套用中序迭代法的模版,对于中间节点的处理跟递归法是一样的。代码如下:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> findMode(TreeNode* root) {int count = 0; //统计频率int MaxCount = 0; //最大频率vector<int> result;TreeNode* pre = nullptr;stack<TreeNode*> st;TreeNode* cur = root;//中序迭代法,向左遍历,将遍历过的元素放入栈中,直到空节点了再将栈中节点取出处理,然后向右遍历//其余思路跟递归法一样,用双指针while (cur != nullptr || !st.empty()) {if (cur != nullptr) {st.push(cur); //指针访问节点,访问到最底层cur = cur->left; //左} else {cur = st.top();st.pop();//中if (pre == nullptr) count = 1; //第一个节点else if (pre->val == cur->val) count++; //与前一个节点数值相同else count = 1; //与前一个节点数值不同pre = cur; //更新前一个节点if (count == MaxCount) result.push_back(cur->val); //如果和最大值相同,放入结果集if (count > MaxCount) { //如果计数大于最大值频率MaxCount = count; //更新最大频率result.clear(); //清空之前最大值频率存的结果集result.push_back(cur->val); //放入当前频率最大的值}cur = cur->right; //右}}return result;}
};
三、 236. 二叉树的最近公共祖先
题目链接
文章讲解
视频讲解
情况一,如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先:
情况二,节点本身p(q),它拥有一个子孙节点q§:
思路:
需要从下往上返回结果才知道p和q的共同祖先是谁。使用后序遍历,将左节点和右节点的结果返回给中间节点。
完整过程如下:
递归法
- 递归函数的参数和返回值:传入树的根节点,递归函数的返回值为数值之和
- 终止条件:如果遍历到空节点,那么左叶子值一定是0;
- 只有当前遍历的节点是父节点,才能判断其子节点是不是左叶子。
- 如果当前遍历的节点是叶子节点,那其左叶子也必定是0;
- 单层递归的逻辑:当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {
public://后序递归//回溯的思想,当找到p和q的时候返回节点给上一层,此时返回的是p和q的位置//上一层同时获取到p和q的节点,那么说明当前节点就是最近公共祖先//将该节点继续返回给上层,此时返回的是公共祖先TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//当root为空返回空,找到p或者q节点向上返回if (!root || root == p || root== q) return root;TreeNode* left = lowestCommonAncestor(root->left, p, q); //向左遍历,找p或q或者公共祖先TreeNode* right = lowestCommonAncestor(root->right, p, q);//向右遍历,找p或q或者公共祖先if (left && right) return root; //p和q分别在当前节点左右侧,说明当前节点是公共祖先else if (!left && right) return right; //只在右节点发现p或者q,或者公共祖先在右节点,将结果返回上层else if (left && !right) return left; //只在左节点发现p或者q,或者公共祖先在右节点,将结果返回上层else return nullptr;}
};
总结
今天主要是学习了:
1.搜索二叉树的对相邻两个节点值的操作,可以使用双指针的方式一前一后操作。
2.通过使用一直清空和更新结果集,可以将本来需要遍历两次的功能只用一次就完成了。
3.有递归就有回溯!从下往上返回结果要用后序遍历,也就是回溯的思想。
明天继续加油!
相关文章:

代码随想录算法训练营day18
代码随想录算法训练营 —day18 文章目录 代码随想录算法训练营前言一、530.二叉搜索树的最小绝对差递归法迭代法 二、501.二叉搜索树中的众数普通二叉树的方法递归法中序迭代法 三、 236. 二叉树的最近公共祖先递归法 总结 前言 今天是算法营的第18天,希望自己能够…...
Kafka安全优化文档:漏洞修复到安全加固
文章目录 1.1.漏洞修复1.1.1.Apache Kafka反序列化漏洞1.1.2.pm2-kafka代码执行漏洞1.1.3.Apache Kafka安全绕过漏洞1.1.4.Apache Kafka Distribution - Schema Repository跨站请求伪造漏洞1.1.5.Apache Kafka输入验证错误漏洞的补丁1.1.6.Apache Kafka信息泄露漏洞1.1.7.Apach…...
Markdown如何添加任务列表-复选框的添加
Markdown如何添加任务列表-复选框的添加 前言语法讲解使用场景及应用实例代码整和渲染结果小结其他文章快来试试吧☺️ Markdown如何添加任务列表-复选框的添加👈点击这里也可查看 前言 To-do任务列表是一种很常见的时间管理工具,它适用于工作计划&…...

基于下垂控制的构网变换器功率控制【微电网变流器】【Simulink】
目录 主要内容 理论研究 整体模型 PQ计算模块 功率控制模块 PWM反馈模块 结果一览 下载链接 主要内容 该仿真针对微电网中分布式电源接入后产生的谐波影响,除了污染网络外,还会恶化微电网变流器输出电流,为了消除谐波影响&a…...

AI定义汽车/跨域融合/整车智能,汽车智能化2.0时代新机会来了
汽车智能化2.0,产业正在发生深度变革。 一方面,AI大模型开始在多个域同步赋能智能汽车,从智能座舱到智能驾驶,再到底盘域,AI大模型正在快速推动汽车变革为超级智能体,AI定义汽车时代开始来临。 另一方面&…...

(leetcode算法题)10. 正则表达式匹配
10. 正则表达式匹配 - 力扣(LeetCode) 此题的要求一个字符串 s 和一个字符规律 p之间支持 . 和 * 的正则表达式匹配 . 匹配任意单个字符 * 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s 的,而不是部分字符串…...

SpringCloudAlibaba实战入门之Sentinel服务降级和服务熔断(十五)
一、Sentinel概述 1、Sentinel是什么 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 一句话概括:sentinel即Hystrix的替代品,官网: https://sentinelguard.io/zh…...

使用爬虫技术获取网页中的半结构化数据
目录 前言1. 半结构化数据与爬虫技术简介1.1 半结构化数据的定义与特性1.2 爬虫技术的基本原理 2. 爬取半结构化数据的实现过程2.1 明确目标与准备2.2 发送HTTP请求2.3 解析网页内容2.4 动态内容的处理2.5 数据存储与清洗 3. 技术挑战与应对策略3.1 处理反爬机制3.2 提高爬取效…...
2025/1/1 路由期末复习作业二
呼呼呼祝大家元旦节快乐啦!(我顶着我超重的黑眼圈说) 昨天一个人在寝室一边吃泡面,一边看步步惊心,一边吃一边哭呜呜呜呜呜若曦为什么不和八爷在一起好好爱,就因为他不当皇帝蛮!难测最是帝王心…...

OpenCV-Python实战(13)——图像轮廓
一、找轮廓 cv2.findContours() contours,hierarchy cv2.findContours(image*,mode*,method*) contours:找到的所有轮廓数组,数组内的元素为轮廓像素点坐标。 hierarchy:轮廓间的层次关系。 image:二值图像(cv2.t…...
javascript变量
变量 命名规范 以 字母、数字、下划线、美元符号 $ 组成、不能以 数字开头、且不能使用 js 中的关键字。 命名规范推荐采用小驼峰 命名法 。类名 采用 大驼峰命名。 var 声明变量的特点 在 script 上下文中定义的是 全局变量,全局变量会自动称为 window的属性。 在…...
在K8S中,如何查看kubelet组件的日志?
在kubernetes中,查看Kubelet组件的日志可以通过几种不同的方法。以下是详细的步骤: 1. 使用journalctl命令: 如果kubelet是通过systemd方式部署,你可以使用journalctl命令来查看其日志。执行journalctl -u kubelet将显示Kubelet…...

android studio android sdk下载地址
android studio安装后,因为公司网络原因,一直无法安装android sdk 后经过手机网络,安装android sdk成功如下,也可以手动下载后指定android sdk本地目录 https://dl.google.com/android/repository/source-35_r01.zip https://dl…...

Fetch处理大模型流式数据请求与解析
为什么有的大模型可以一次返回多个 data? Server-Sent Events (SSE):允许服务器连续发送多个 data: 行,每个代表一个独立的数据块。 流式响应:大模型服务通常以流式响应方式返回数据,提高响应速度。 批量处理&#x…...

FPGA自学之路:到底有多崎岖?
FPGA,即现场可编程门阵列,被誉为硬件世界的“瑞士军刀”,其灵活性和可编程性让无数开发者为之倾倒。但谈及FPGA的学习难度,不少人望而却步。那么,FPGA自学之路到底有多崎岖呢? 几座大山那么高?…...

从0到机器视觉工程师(二):封装调用静态库和动态库
目录 静态库 编写静态库 使用静态库 方案一 方案二 动态库 编写动态库 使用动态库 方案一 方案二 方案三 总结 静态库 静态库是在编译时将库的代码合并到最终可执行程序中的库。静态库的优势是在编译时将所有代码包含在程序中,可以使程序独立运行&…...

[极客大挑战 2019]Knife1
这里很显然,根据提示可以猜测,已经有一句话木马上传了,但是路径这里不是很清楚,不知道路径在哪里,不过还是用菜刀连一下试试: 连接成功,在根目录下发现flag。不过如果不用菜刀,可以用…...
【在Python中生成随机字符串】
在Python中生成随机字符串,你可以结合使用random模块和字符串操作。以下是一个常用的方法,通过从预定义的字符集中随机选择字符来构建字符串: import random import stringdef generate_random_string(length):# 定义字符集:可以…...
【three.js】场景搭建
three.js由场景、相机、渲染器、灯光、控制器等几个要素组成。每个要素都有不同的类型,例如光照有太阳光、环境光、半球光等等。每种光照都有不同的属性可以进行配置。 场景 场景(scene):场景是所有物体的容器,如果要…...
Singleton: WebRTC中ThreadManager中的单例模式
1. 什么是单例模式: 旨在确保一个类只有一个实例,并提供全局访问点。 应用场景:需要一个全局唯一的实例,避免资源浪费。 2. 单例模式的实现: Lazy Initialization(懒汉式)(延迟初…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...
怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)
+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...
[特殊字符] Spring Boot底层原理深度解析与高级面试题精析
一、Spring Boot底层原理详解 Spring Boot的核心设计哲学是约定优于配置和自动装配,通过简化传统Spring应用的初始化和配置流程,显著提升开发效率。其底层原理可拆解为以下核心机制: 自动装配(Auto-Configuration) 核…...
MeanFlow:何凯明新作,单步去噪图像生成新SOTA
1.简介 这篇文章介绍了一种名为MeanFlow的新型生成模型框架,旨在通过单步生成过程高效地将先验分布转换为数据分布。文章的核心创新在于引入了平均速度的概念,这一概念的引入使得模型能够通过单次函数评估完成从先验分布到数据分布的转换,显…...

2025-06-08-深度学习网络介绍(语义分割,实例分割,目标检测)
深度学习网络介绍(语义分割,实例分割,目标检测) 前言 在开始这篇文章之前,我们得首先弄明白,什么是图像分割? 我们知道一个图像只不过是许多像素的集合。图像分割分类是对图像中属于特定类别的像素进行分类的过程,即像素级别的…...