代码随想录算法训练营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(懒汉式)(延迟初…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...