leetcode每日一题41

99. 恢复二叉搜索树

中序遍历树,找到逆序的两个数,交换
有两种情况
如果是像示例1一样的,中序遍历后是3,2,1
是连续的两个逆序,那么交换第一,第三个数
如果是像示例2一样,中序遍历后是1,3,4,2
是一个逆序,那么交换这两个数即可

class Solution {
public:vector<int> vec;void traversal(TreeNode* root){if(root==nullptr)return;traversal(root->left);vec.push_back(root->val);traversal(root->right);}void recover(TreeNode* root,int count,int x,int y){if(root!=nullptr){if(root->val==x||root->val==y){if(root->val==x)root->val=y;else root->val=x;if(--count==0)return;}}if (root->left != nullptr) {recover(root->left, count, x, y);}if (root->right != nullptr) {recover(root->right, count, x, y);}return;}int index1=-1,index2=-1;void recoverTree(TreeNode* root) {traversal(root);for(int i=1;i<vec.size();i++){if(vec[i-1]>vec[i]){index2=i;if(index1==-1)index1=i-1;else break;}}cout<<index1<<index2<<endl;recover(root,2,vec[index1],vec[index2]);}
};

102.二叉树的层序遍历

模板,记住就行了
借用⼀个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,
用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
用result保存层序遍历的结果
用vec保存一层的结果
用que保存该层的子节点

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;if(root!=nullptr)que.push(root);vector<vector<int>> result;while(!que.empty()){int size=que.size();vector<int> vec;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}result.push_back(vec);}return result;}
};

103.二叉树的锯齿形层序遍历

在奇数次遍历次数时,reverse一下该层vec就行了

class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {queue<TreeNode*> que;int level=0;if(root!=nullptr)que.push(root);vector<vector<int>> result;while(!que.empty()){int size=que.size();vector<int> vec;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}if(level%2)reverse(vec.begin(),vec.end());level++;result.push_back(vec);}return result;}
};

或者使用双端队列deque保存该层的节点

class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {queue<TreeNode*> que;if(root!=nullptr)que.push(root);vector<vector<int>> result;bool isOrderLeft = true;while(!que.empty()){int size=que.size();deque<int> level;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();if(isOrderLeft)level.push_back(node->val);else level.push_front(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}isOrderLeft=!isOrderLeft;result.push_back(vector<int>{level.begin(), level.end()});}return result;}
};

105. 从前序与中序遍历序列构造二叉树

用前序遍历的节点分割中序遍历序列
将中序遍历分为左右子树
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取前序数组第一个元素作为节点元素。
第三步:找到前序数组第一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,⼀定是先
切中序数组)
第五步:切割前序数组,切成前序左数组和前序右数组
第六步:递归处理左区间和右区间
模板:

TreeNode* traversal (vector& preorder, vector& inorder) {
// 第一步
if (preorder.size() == 0) return NULL;
// 第二步:前序遍历数组第一个元素,就是当前的中间节点
int rootValue = preorder[preorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
// 叶子节点
if (preorder.size() == 1) return root;
// 第三步:找切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size();
delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 第四步:切割中序数组,得到 中序左数组和中序右数组
// 第五步:切割前序数组,得到前序左数组和前序右数组
// 第六步
root->left = traversal(前序左数组, 中序左数组);
root->right = traversal(前序右数组, 中序右数组);
return root;
}

此时应该注意确定切割的标准,是左闭右开,还有左开又闭,还是左闭又闭,这个就是不变量,要在递归中保持这个不变量。

class Solution {
public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {// 第一步if (preorder.size() == 0) return NULL;// 第二步:前序遍历数组第一个元素,就是当前的中间节点int rootValue = preorder[0];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (preorder.size() == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组vector<int> leftInorder(inorder.begin(), inorder.begin() +
delimiterIndex);vector<int> rightInorder(inorder.begin() + delimiterIndex + 1,
inorder.end() );// 第五步:切割前序数组,得到前序左数组和前序右数组vector<int>::iterator it = preorder.begin();preorder.erase(it);vector<int> leftPreorder(preorder.begin(), preorder.begin()
+ leftInorder.size());vector<int> rightPreorder(preorder.begin() +
leftInorder.size(), preorder.end());// 第六步root->left = buildTree(leftPreorder, leftInorder);root->right = buildTree(rightPreorder, rightInorder);return root;}
};

这个代码性能并不好,因为代码里每层递归都定义了新的vector,既耗时又耗空间
可以用索引的方式重新写这个代码

class Solution {
public:TreeNode* traversal(vector<int>& preorder,int preorderBegin,int preorderEnd, vector<int>& inorder,int inorderBegin,int inorderEnd){// 第一步if (preorderBegin >= preorderEnd) return NULL;// 第二步:前序遍历数组第一个元素,就是当前的中间节点int rootValue = preorder[preorderBegin];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (preorderEnd - preorderBegin == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组int leftInorderBegin = inorderBegin;int leftInorderEnd = delimiterIndex;int rightInorderBegin = delimiterIndex + 1;int rightInorderEnd = inorderEnd;// 第五步:切割前序数组,得到前序左数组和前序右数组int leftPreorderBegin = preorderBegin+1;int leftPreorderEnd = preorderBegin + 1 + delimiterIndex -
inorderBegin;int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex -
inorderBegin);int rightPreorderEnd = preorderEnd;// 第六步root->left = traversal(preorder,leftPreorderBegin,leftPreorderEnd, inorder,leftInorderBegin,leftInorderEnd);root->right = traversal(preorder,rightPreorderBegin,rightPreorderEnd, inorder,rightInorderBegin,rightInorderEnd);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {if (preorder.size() == 0) return NULL;TreeNode* node=traversal(preorder,0,preorder.size(),inorder,0,inorder.size());return node;}
};

106.从中序与后序遍历序列构造二叉树

和上道题类似,用后序的最后一个节点分割中序序列

/*** 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:TreeNode* traversal(vector<int>& inorder,int inorderBegin,int inorderEnd,vector<int>& postorder,int postorderBegin,int postorderEnd){// 第一步if (postorderBegin >= postorderEnd) return NULL;// 第二步:后序遍历数组最后一个元素,就是当前的中间节点int rootValue = postorder[postorderEnd-1];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (postorderEnd - postorderBegin == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组int leftInorderBegin = inorderBegin;int leftInorderEnd = delimiterIndex;int rightInorderBegin = delimiterIndex + 1;int rightInorderEnd = inorderEnd;// 第五步:切割后序数组,得到后序左数组和后序右数组int leftPostorderBegin = postorderBegin;int leftPostorderEnd = postorderBegin + delimiterIndex -
inorderBegin;int rightPostorderBegin = postorderBegin + (delimiterIndex -
inorderBegin);int rightPostorderEnd = postorderEnd-1;// 第六步root->left = traversal(inorder,leftInorderBegin,leftInorderEnd, postorder,leftPostorderBegin,leftPostorderEnd);root->right = traversal(inorder,rightInorderBegin,rightInorderEnd, postorder,rightPostorderBegin,rightPostorderEnd);return root;}TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {if(inorder.size()==0)return NULL;TreeNode* node = traversal(inorder,0,inorder.size(),postorder,0,postorder.size());return node;}
};

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

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

相关文章

Debezium发布历史35

原文地址&#xff1a; https://debezium.io/blog/2018/07/19/advantages-of-log-based-change-data-capture/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 基于日志的变更数据捕获的五个优点 七月 19, 2018 作…

github鉴权失败

问题&#xff1a; 如上图所示 git push 时发生了报错&#xff0c;鉴权失败&#xff1b; 解决方案 Settings->Developer settings->Personal access tokens->Generate new token。创建新的访问密钥&#xff0c;勾选repo栏&#xff0c;选择有效期&#xff0c;为密钥命…

【C#与Redis】--高级主题--Redis 管道

一、引言 1.1 概念介绍 Redis管道是一种用于优化多个命令执行的机制&#xff0c;允许客户端将多个命令一次性发送给服务器&#xff0c;然后一次性接收所有命令的返回结果。这种机制可以减少客户端与服务器之间的网络往返次数&#xff0c;从而提高性能。 1.2 作用 提高性能&…

java 对数转换log_a {c}

1、换底公式 l o g a c l o g x c l o g x a log_a c \frac{log_x c}{log_x a} loga​clogx​alogx​c​ 2、推理过程 有&#xff1a; a b c &#xff0c;证明 l o g a c l o g x c l o g x a 取对数 ( l o g x ) &#xff1a; l o g x a b l o g x c l o g x a b b ∗ …

鸿蒙HarmonyOS-图表应用

简介 随着移动应用的不断发展&#xff0c;数据可视化成为提高用户体验和数据交流的重要手段之一。在HarmonyOS应用开发中&#xff0c;一个强大而灵活的图表库是实现这一目标的关键。而MPChart就是这样一款图表库&#xff0c;它为开发者提供了丰富的功能和灵活性&#xff0c;使得…

【持续更新ing】uniapp+springboot实现个人备忘录系统【前后端分离】

目录 &#xff08;1&#xff09;项目可行性分析 &#xff08;2&#xff09;需求描述 &#xff08;3&#xff09;界面原型 &#xff08;4&#xff09;数据库设计 &#xff08;5&#xff09;后端工程 接下来我们使用uniappspringboot实现一个简单的前后端分离的小项目----个…

Spark作业的调度与执行流程

Apache Spark是一个分布式计算框架&#xff0c;用于处理大规模数据。了解Spark作业的调度与执行流程是构建高效分布式应用程序的关键。本文将深入探讨Spark作业的组成部分、调度过程以及执行流程&#xff0c;并提供丰富的示例代码来帮助大家更好地理解这些概念。 Spark作业的组…

第09章:随堂复习与企业真题(异常处理)

来源&#xff1a;尚硅谷Java零基础全套视频教程(宋红康2023版&#xff0c;java入门自学必备) 基本都是宋老师发的资料里面的内容&#xff0c;只不过补充几个资料里没直接给出答案的问题的答案。 不想安装markdown笔记的app所以干脆在这里发一遍。 第09章&#xff1a;随堂复习…

[Angular] 笔记 16:模板驱动表单 - 选择框与选项

油管视频&#xff1a; Select & Option (Template Driven Forms) Select & Option 在 pokemon.ts 中新增 interface: export interface Pokemon {id: number;name: string;type: string;isCool: boolean;isStylish: boolean;acceptTerms: boolean; }// new interface…

前端图片适配不同屏幕方案

预备知识&#xff1a; 设备独立像素,以下图的iphone12 Pro为例&#xff0c;390*844表示的就是设备独立像素&#xff08;DIP&#xff09;,也可以理解为CSS像素 物理像素&#xff08;设备像素&#xff09;&#xff0c;就是屏幕的分辨率&#xff0c;显示屏就是由一个个物理像素…

QT/C++ 远程数据采集上位机+服务器

一、项目介绍&#xff1a; 远程数据采集与传输 课题要求:编写个基于TCP的网络数据获取与传输的应用程序; 该程序具备以下功能: 1)本地端程序够通过串口与下位机(单片机)进行通信&#xff0c;实现数据采集任务 2)本地端程序能将所获取下位机数据进行保存(如csv文本格式等); 3…

初识隧道代理HTTP:理解基础概念的重要性

嗨&#xff0c;小伙伴们&#xff01;如果你对网络世界充满好奇&#xff0c;那么这篇文章就是为你准备的。我们将一起踏上一段奇妙的旅程&#xff0c;探索一个叫做“隧道代理HTTP”的新领域。但在这之前&#xff0c;我们需要先穿上“基础概念”的防护服&#xff0c;以免被这个复…

axios配置代理

ChatGPT&#xff08;3.5/4.0&#xff09;国内镜像&#xff1a;https://www.atalk-ai.com/ 在Node.js中&#xff0c;你可以使用axios库来发送HTTP请求&#xff0c;并且可以配置它来使用代理服务器。以下是如何配置axios以通过位于127.0.0.1:15236的代理服务器发送请求的例子&am…

MR实战:实现数据去重

文章目录 一、实战概述二、提出任务三、完成任务&#xff08;一&#xff09;准备数据文件1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 &#xff08;二&#xff09;实现步骤1、Map阶段实现&#xff08;1&#xff09;创建Maven项目&#xff08;2&#xff09;添加相关依赖…

一语道破爬虫,来揭开爬虫面纱

目录 一、爬虫&#xff08;网络蜘蛛(Spider)&#xff09; 1.1、是什么&#xff1a; 1.2、学习的原因 1.3、用在地方&#xff1a; 1.4、是否合法&#xff1a; 1.5、后果 案例&#xff1a; 二、应用领域 三、Robots协议 四、抓包 4.1、浏览器抓包 4.2、抓包工具 常见…

从0到1浅析Redis服务器反弹Shell那些事

文章目录 前言Redis服务1.1 特点与应用1.2 安装与使用1.3 语法和配置1.4 未授权访问 反弹Shell2.1 Web服务写入Webshell2.2 Linux定时任务反弹shell2.3 /etc/profile.d->反弹shell2.4 写入ssh公钥登录服务器2.5 利用Redis主从复制RCE2.6 SSRF漏洞组合拳->RCE 总结 前言 …

2023年终-顺势而为

疫情以来&#xff0c;越来越感觉到顺势的重要性&#xff0c;就像一个人走路一样&#xff0c;如果方向错了&#xff0c;会绕很多弯才能到达终点。 雷军说&#xff0c;站在风口上猪都能飞起来。 很多人明白这个道理&#xff0c;但是去付出实践的人不多。第一&#xff0c;不愿意进…

stm32中的i2c协议

stm32中I2C 文章目录 stm32中I2CI2C 协议简介I2C物理层协议层I2C基本读写过程 **通讯的起始和停止信号****数据有效性****地址及数据方向****响应** STM32的I2C特性及架构**STM32** **的** I2C外设简介STM32 的 I 2C 架构剖析通讯引脚 通讯过程主发送器主接收器 I2C初始化结构体…

【Linux】指令(本人使用比较少的)——笔记(持续更新)

文章目录 ps -axj&#xff1a;查看进程ps -aL&#xff1a;查看线程echo $?&#xff1a;查看最近程序的退出码jobs&#xff1a;查看后台运行的线程组fd 任务号&#xff1a;将后台任务提到前台bg 任务号&#xff1a;将暂停的后台程序重启netstat -nltp&#xff1a;查看服务及监听…

Unity Meta Quest 一体机开发(十二):【手势追踪】Poke 交互 - 用手指点击由 3D 物体制作的 UI 按钮

文章目录 &#x1f4d5;教程说明&#x1f4d5;给玩家配置 HandPokeInteractor&#x1f4d5;用 3D 物体制作可以被点击的 UI 按钮⭐搭建物体层级⭐给物体添加脚本⭐为脚本变量赋值 &#x1f4d5;模仿官方样例按钮的样式&#x1f4d5;在按钮上添加文字&#x1f4d5;修改按钮图片 …