剑指offer刷题记录Day2 07.数组中重复的数字 ---> 11.旋转数组的最小数字

名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪)
创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)

目录

        • 1、重建二叉树
          • ①代码实现(带注释)
          • ②补充说明(前序遍历和中序遍历重建二叉树的原理)
        • 2、二叉树的下一个结点
          • ①代码实现(带注释)
        • 3、用两个栈实现队列
          • ①代码实现(带注释)
          • ②补充说明(栈和队列)
        • 4、斐波那契数列
          • ①代码实现(带注释)
          • ②补充说明(斐波那契数列)
        • 5、旋转数组的最小数字
          • ①代码实现(带注释)
          • ②补充说明(二分搜索法)

1、重建二叉树

原题链接:07.重建二叉树

在这里插入图片描述

①代码实现(带注释)
#include <unordered_map>
#include <vector>
/*** struct TreeNode {*  int val;*  struct TreeNode *left;*  struct TreeNode *right;*  TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* };*/
/*解题关键:前序序列中的第一个元素总是树的根。
通过这个根,我们可以在中序序列中找到根的索引位置。中序序列又总是被根索引分成两部分:左子树和右子树。
同样地,我们就能够可以确定前序序列中左右子树的边界。最后通过递归这个过程来重建整棵树即可解决问题。*/class Solution {public:unordered_map<int, int>indexMap; // 用于快速访问中序遍历中值的索引的映射TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder,int preorderStart, int preorderEnd, int inorderStart, int inorderEnd) {//若前序遍历的起始位置大于结束位置               if (preorderStart > preorderEnd) {return nullptr; //若返回 nullptr ,表示该子树不存在任何节点。}// 根据前序遍历的特点,我们可以从前序遍历获取根节点值int rootVal = preorder[preorderStart]; // 创建原二叉树的根节点TreeNode* root = new TreeNode(rootVal); // 在中序遍历中找到根的索引下标int rootIndexInInorder = indexMap[rootVal]; // leftElements:左子树中的元素数量int leftElements = rootIndexInInorder - inorderStart;// 递归构建左子树root->left = buildTree(preorder, inorder, preorderStart + 1,preorderStart + leftElements, inorderStart, rootIndexInInorder - 1);// 递归构建右子树root->right = buildTree(preorder, inorder, preorderStart + leftElements + 1,preorderEnd, rootIndexInInorder + 1, inorderEnd);//返回每次所构建子树的根节点return root;}TreeNode* reConstructBinaryTree(vector<int>& preOrder, vector<int>& vinOrder) {int n = preOrder.size();// 填充indexMap以便快速访问中序遍历中的索引/*在重建二叉树的过程中,需要频繁地找到前序遍历中的根节点在中序遍历序列中的位置,这样才能确定左右子树的范围,因此此处使用了映射。如果不使用映射,每次查找都可能需要遍历整个中序遍历序列来找到根节点的位置*/for (int i = 0; i < n; i++) {indexMap[vinOrder[i]] = i;}return buildTree(preOrder, vinOrder, 0, n - 1, 0, n - 1);}
};

在这里插入图片描述

②补充说明(前序遍历和中序遍历重建二叉树的原理)

该题根据前序遍历和中序遍历重建二叉树的原理是什么?

构建二叉树的原理依赖于前序遍历和中序遍历的特性来确定树的结构。前序遍历的顺序是根 左 右。中序遍历的顺序是左 根 右。

根据前序遍历和中序遍历构建二叉树的步骤:

  1. 确定根节点:在前序遍历中,序列的第一个元素总是树的根节点。

  2. 划分左右子树:在中序遍历中,根节点将序列分为两部分,左边是树的左子树,右边是树的右子树。

  3. 递归构建:利用上一步得到的左右子树的中序遍历序列,和从前序遍历序列中提取相应的左右子树序列,递归地重复上述过程构建整棵树。

例如,假设有一棵树的前序遍历序列是 [ A , B , D , E , C , F ] [\text{A}, \text{B}, \text{D}, \text{E}, \text{C}, \text{F}] [A,B,D,E,C,F],中序遍历序列是 [ D , B , E , A , C , F ] [\text{D}, \text{B}, \text{E}, \text{A}, \text{C}, \text{F}] [D,B,E,A,C,F]

  1. 前序遍历的第一个元素是 A A A,所以 A A A 是根节点。

  2. 在中序遍历中, A A A 前面的 [ D , B , E ] [\text{D}, \text{B}, \text{E}] [D,B,E] 是左子树的中序遍历序列, A A A 后面的 [ C , F ] [\text{C}, \text{F}] [C,F] 是右子树的中序遍历序列。

  3. 递归构建左子树和右子树。

    • 对于左子树,前序遍历序列变为 [ B , D , E ] [\text{B}, \text{D}, \text{E}] [B,D,E],中序遍历序列是 [ D , B , E ] [\text{D}, \text{B}, \text{E}] [D,B,E]。重复上述步骤,可以构建出左子树。
    • 对于右子树,前序遍历序列是 [ C , F ] [\text{C}, \text{F}] [C,F],中序遍历序列是 [ C , F ] [\text{C}, \text{F}] [C,F]。重复上述步骤,可以构建出右子树。

通过这种方式,我们就可以准确地重建原始的二叉树结构了。

2、二叉树的下一个结点

原题链接:08.二叉树的下一个结点

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

①代码实现(带注释)
/*
struct TreeLinkNode {int val;struct TreeLinkNode *left;struct TreeLinkNode *right;struct TreeLinkNode *next;TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {}
};
*/
class Solution {public:// 定义树节点指针向量nodes 用于存储中序遍历所有节点指针vector<TreeLinkNode*> nodes;// 获取给定节点的下一个节点TreeLinkNode* GetNext(TreeLinkNode* pNode) {TreeLinkNode* root = pNode;// 循环遍历找到根节点while (root->next) root = root->next;// 对树进行中序遍历,并将节点指针存储在nodes向量中InOrder(root); int n = nodes.size(); // 获取遍历后得到的节点总数// 遍历节点,查找给定节点的下一个节点for (int i = 0; i < n - 1; i++) {TreeLinkNode* cur = nodes[i];// 如果当前节点是给定节点if (pNode == cur) { // 则返回下一个节点return nodes[i +1]; }}// 若给定节点没有下一个节点,则返回NULLreturn NULL; }// 中序遍历二叉树void InOrder(TreeLinkNode* root) {if (root == NULL) return;InOrder(root->left); // 遍历左子树//push_back函数可以在Vector向量最后添加一个元素(括号中的参数为要插入的值)nodes.push_back(root); // 访问当前节点InOrder(root->right); // 遍历右子树}
};

在这里插入图片描述

3、用两个栈实现队列

原题链接:09.用两个栈实现队列

在这里插入图片描述

①代码实现(带注释)
class Solution
{
public://使用两个栈实现队列的push操作void push(int node) {stack1.push(node); //直接将元素压入stack1}//使用两个栈实现队列的pop操作int pop() {//如果stack2为空,则将stack1中的所有元素转移到stack2中if (stack2.empty()) {while (!stack1.empty()) {//将stack1的栈顶元素压入stack2stack2.push(stack1.top());//删除stack1的栈顶元素stack1.pop();}}//如果stack2不为空,则直接从stack2中弹出栈顶元素,即队头元素//获取stack2的栈顶元素int head = stack2.top(); //删除stack2的栈顶元素stack2.pop();//返回队头元素return head;}private:stack<int> stack1;//栈1用于插入操作stack<int> stack2;//栈2用于删除操作
};

在这里插入图片描述

②补充说明(栈和队列)

栈(Stack)和队列(Queue)是两种基本的数据结构,它们在处理数据的方式上有着本质的区别:

  • 是一种后进先出的数据结构。
    最后添加进栈的元素将是第一个被移除的。想象一下一叠盘子,你只能从顶部添加或移除盘子。常见的操作包括“push”(添加一个元素到栈顶)和“pop”(移除栈顶元素)。

  • 队列 是一种先进先出的数据结构。
    第一个添加进队列的元素将是第一个被移除的。可以想象成在银行排队,新来的顾客排在队伍的末尾,而服务员从队伍的前端开始服务顾客。常见的操作包括“enqueue”(将一个元素添加到队列末尾)和“dequeue”(移除队列前端的元素)。

4、斐波那契数列

原题链接:10. 斐波那契数列
在这里插入图片描述

①代码实现(带注释)
class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param n int整型 * @return int整型*/int Fibonacci(int n) {//处理边界情况if(n <= 1)return n;//初始化前两个斐波那契数	int a=0,b=1;//计算第n项for(int i = 2; i <= n; i++){//更新斐波那契数到第n项int next = a+b;a = b;b = next;}//第n项的斐波那契数列return b;}
};

在这里插入图片描述

②补充说明(斐波那契数列)

斐波那契数列是一种在数学和计算机科学中广泛应用的数列。它由以下递归关系定义:每个数是前两个数的和,其最初两个数通常定义为 F ( 0 ) = 0 , F ( 1 ) = 1 F(0) = 0, F(1) = 1 F(0)=0,F(1)=1。因此,斐波那契数列的开始部分是:

0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , … 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, \ldots 0,1,1,2,3,5,8,13,21,34,

形式上,斐波那契数列可以用数学公式表示为:

F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n) = F(n-1) + F(n-2) F(n)=F(n1)+F(n2)

其中, n ≥ 2 n \geq 2 n2 F ( 0 ) = 0 F(0) = 0 F(0)=0, F ( 1 ) = 1 F(1) = 1 F(1)=1

特点:除了最开始的两个数字外,每个数字都是其前两个数字的和。

5、旋转数组的最小数字

原题链接:11. 旋转数组的最小数字

在这里插入图片描述

①代码实现(带注释)
class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param nums int整型vector * @return int整型*//*由于数组原本是非降序排列的,旋转后,数组被分成两个非降序的子数组。最小值是这两个子数组的分界点。 因此我们可以使用二分搜索法/折半查找法来优化搜索过程,这样时间复杂度就是O(logn)。*/ int minNumberInRotateArray(vector<int>& nums) {//如果数组为空,返回-1if(nums.empty()) return -1; //定义左侧left位置为0int left = 0;//右侧right位置为n-1int right = nums.size() - 1;//如果旋转数组没有旋转(例如[1,2,3,4,5]变成[1,2,3,4,5]),直接返回第一个元素if(nums[left] < nums[right]){return nums[left];}//二分查找while (left < right) {int mid = left + (right - left) / 2;if(nums[mid] > nums[right]){//[mid+1,right]区间left = mid + 1;}else if (nums[mid] < nums[right]) {//[left,mid]区间right = mid;}else {//当中间值和右边值相等时,缩小范围right--;}}//循环结束,此时left == right,指向的就是数组中的最小值return nums[left];}
};

在这里插入图片描述

②补充说明(二分搜索法)

二分搜索法(Binary Search)是一种在有序数组中查找特定元素的高效算法。

原理:将待搜索的数组分成两半,然后根据中间元素与目标值的比较结果来确定下一步搜索的区域,从而逐步缩小搜索范围,直到找到目标值或确定目标值不存在。

二分搜索的基本步骤如下:

  1. 确定搜索区间:初始搜索区间为整个数组。
  2. 找到中间元素:计算搜索区间的中点位置,取出中间元素进行比较。
  3. 比较中间元素与目标值
    • 如果中间元素正好等于目标值,则搜索成功。
    • 如果中间元素小于目标值,则将搜索区间调整为中间元素右侧的子区间,继续搜索。
    • 如果中间元素大于目标值,则将搜索区间调整为中间元素左侧的子区间,继续搜索。
  4. 重复步骤2和3,直到找到目标值或搜索区间为空(表示目标值不存在于数组中)。

二分搜索的效率较高,其时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组的长度。因此本题采用二分搜索法,可以帮助我们在查找数据时节省大量的时间。

很感谢你能看到这里,如有相关疑问,还请下方评论留言。
Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
如果大家喜欢的话,请动动手点个赞和关注吧,非常感谢你们的支持!

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

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

相关文章

YOLOv9有效改进|使用动态蛇形卷积Dynamic Snake Convolution

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 使用ICCV2023中的动态蛇形卷积替换YOLOv9网络中的Conv模块。 二、Dynamic Snake Convolution模块详解 2.1 模块简介 应用场景&#x…

【Micropython基础】TCP客户端与服务器

文章目录 前言一、连接Wifi1.1 创建STA接口1.2 激活wifi接口1.3 连接WIFI1.4 判断WIFI是否连接1.5 连接WIFI总体代码 二、创建TCP 客户端2.1 创建套接字2.2 设置TCP服务器的ip地址和端口2.3 连接TCP服务器2.3 发送数据2.4 接收数据2.5 断开连接2.6 示例代码 三、TCP服务器的创建…

JVM运行时数据区——运行时数据区及线程概述

文章目录 1、运行时数据区概述2、线程3、小结 内存是非常重要的系统资源&#xff0c;是硬盘和CPU的中间仓库及桥梁&#xff0c;承载着操作系统和应用程序的实时运行。JVM在程序执行期间把它所管理的内存分为若干个不同的数据区域。这些不同的数据区域可以分为两种类型&#xff…

Topaz Gigapixel AI:让每一张照片都焕发新生mac/win版

Topaz Gigapixel AI 是一款革命性的图像增强软件&#xff0c;它利用先进的人工智能技术&#xff0c;能够显著提升图像的分辨率和质量。无论是摄影爱好者还是专业摄影师&#xff0c;这款软件都能帮助他们将模糊的、低分辨率的照片转化为清晰、细腻的高分辨率图像。 Topaz Gigap…

【探索Linux】—— 强大的命令行工具 P.24(网络基础)

阅读导航 引言一、计算机网络背景1. 网络发展历史 二、认识 "协议"1. 网络协议概念2. 网络协议初识&#xff08;1&#xff09;协议分层&#xff08;2&#xff09;OSI参考模型&#xff08;Open Systems Interconnection Reference Model&#xff09;&#xff08;3&…

差分题练习(区间更新)

一、差分的特点和原理 对于一个数组a[]&#xff0c;差分数组diff[]的定义是: 对差分数组做前缀和可以还原为原数组: 利用差分数组可以实现快速的区间修改&#xff0c;下面是将区间[l, r]都加上x的方法: diff[l] x; diff[r 1] - x;在修改完成后&#xff0c;需要做前缀和恢复…

智慧应急:构建全方位、立体化的安全保障网络

一、引言 在信息化、智能化快速发展的今天&#xff0c;传统的应急管理模式已难以满足现代社会对安全保障的需求。智慧应急作为一种全新的安全管理模式&#xff0c;旨在通过集成物联网、大数据、云计算、人工智能等先进技术&#xff0c;实现对应急事件的快速响应、精准决策和高…

【IDEA+通义灵码插件】实现属于你的大模型编程助手

目录 1.前言 2.下载安装 3.解释代码 4.生成单元测试 5.生成注释 6.智能补全 1.前言 大模型到底该以一种什么方式落地&#xff0c;从而嵌入我们的工作当中&#xff0c;助力我们工作效率的提升&#xff0c;其实最好的方式也许就是虚拟助手的方式&#xff0c;就像钢铁侠的&…

最新发布!2D激光雷达与相机数据融合的新方法

作者&#xff1a;小柠檬 | 编辑&#xff1a;3DCV 在公众号「3DCV」后台&#xff0c;回复「原论文」获取论文 添加微信&#xff1a;dddvision&#xff0c;备注&#xff1a;3D高斯&#xff0c;拉你入群。文末附行业细分群 原文&#xff1a;最新发布&#xff01;2D激光雷达与相…

【飞桨EasyDL】飞桨EasyDL发布的模型转换onnx(附工程代码)

一个愿意伫立在巨人肩膀上的农民...... 一、paddle转onnx转rknn环境搭建 paddle转onnx和onnx转rknn两个环境可以分开搭建&#xff0c;也可以搭建在一起。这里选择分开搭建&#xff0c;先搭建paddle转onnx。 1.1、创建环境 选择python3.8.13包进行创建环境 conda create --nam…

SQL 练习题目(入门级)

今天发现了一个练习SQL的网站--牛客网。里面题目挺多的&#xff0c;按照入门、简单、中等、困难进行了分类&#xff0c;可以直接在线输入SQL语句验证是否正确&#xff0c;并且提供了测试表的创建语句&#xff0c;也可以方便自己拓展练习&#xff0c;感觉还是很不错的一个网站&a…

项目实战:Qt监测操作系统物理网卡通断v1.1.0(支持windows、linux、国产麒麟系统)

若该文为原创文章&#xff0c;转载请注明出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/136276999 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

Logic Pro:专业音乐制作软件,为你的音乐插上翅膀

Logic Pro是一款功能强大的音乐制作软件&#xff0c;专为专业音乐人和音乐爱好者设计。它提供了全面的音乐创作工具&#xff0c;包括音频录音、编辑、混音、合成以及自动化等功能&#xff0c;让你能够轻松实现音乐梦想。 Logic Pro软件获取 首先&#xff0c;Logic Pro拥有卓越…

使用 Azure 部署静态网页

Author&#xff1a;AXYZdong 硕士在读 工科男 有一点思考&#xff0c;有一点想法&#xff0c;有一点理性&#xff01; 定个小小目标&#xff0c;努力成为习惯&#xff01;在最美的年华遇见更好的自己&#xff01; CSDNAXYZdong&#xff0c;CSDN首发&#xff0c;AXYZdong原创 唯…

【airtest】自动化入门教程(一)AirtestIDE

目录 一、下载与安装 1、下载 2、安装 3、打开软件 二、web自动化配置 1、配置chrome浏览器 2、窗口勾选selenium window 三、新建项目&#xff08;web&#xff09; 1、新建一个Airtest项目 2、初始化代码 3、打开一个网页 四、恢复默认布局 五、新建项目&#xf…

[业务系统]人物坐骑系统介绍I

1.问题描述 旧版本的坐骑系统依赖于人物装备了【法宝】&#xff08;一种装备类型&#xff09;&#xff0c;装备了法宝的人物变拥有了【幻化】坐骑的能力&#xff0c;即在人物装备栏中的【外观】中会有已经幻化和未幻化&#xff08;解锁&#xff09;的坐骑。如果玩家至少幻化一…

基于R语言的分位数回归技术应用

回归是科研中最常见的统计学研究方法之一&#xff0c;在研究变量间关系方面有着极其广泛的应用。由于其基本假设的限制&#xff0c;包括线性回归及广义线性回归在内的各种常见的回归方法都有三个重大缺陷&#xff1a;(1)对于异常值非常敏感&#xff0c;极少量的异常值可能导致结…

(全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF

研究生英语读写教程基础级教师用书PDF 研究生英语读写教程提高级教师用书PDF pdf下载&#xff08;完整版下载&#xff09; &#xff08;1&#xff09;研究生英语读写教程基础级教师用书PDF &#xff08;2&#xff09;研究生英语读写教程基提高级教师用书PDF

【C++那些事儿】深入理解C++类与对象:从概念到实践(中)| 默认构造函数 | 拷贝构造函数 | 析构函数 | 运算符重载 | const成员函数

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C那些事儿 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 1. 类的6个默认成员函数2. 构造函数2.1 概念2.2 特性 3. 析构函数3.1 概念3.2 特性 4. 拷贝…

GO-接口

1. 接口 在Go语言中接口&#xff08;interface&#xff09;是一种类型&#xff0c;一种抽象的类型。 interface是一组method的集合&#xff0c;接口做的事情就像是定义一个协议&#xff08;规则&#xff09;&#xff0c;只要一台机器有洗衣服和甩干的功能&#xff0c;我就称它…