【LeetCode刷题之路】622.设计循环队列
LeetCode刷题记录 |
- 🌐 我的博客主页:iiiiiankor
- 🎯 如果你觉得我的内容对你有帮助,不妨点个赞👍、留个评论✍,或者收藏⭐,让我们一起进步!
- 📝 专栏系列:LeetCode 刷题日志
- 🌱 文章内容来自我的学习与实践经验,如果你有任何想法或问题,欢迎随时在评论区交流讨论。让我们一起探索更多的可能!🚀
文章目录
- 🚀LeetCode622.设计循环队列
- 一、🌟题目描述🌟
- 二、🎨分析🎨
- 链表实现分析
- 三、💥题解💥
- 定义队列结构
- Create(创建队列)
- 判断是否为空
- 判断是不是满了
- 获取队头元素
- 获取队尾元素
- push接口
- pop接口
- 销毁
- ✏️总代码✏️
- 💥💥最后贴一个题 💥💥
🚀LeetCode622.设计循环队列
链接:LeetCode622.设计循环队列
一、🌟题目描述🌟
二、🎨分析🎨
- 题目理解:
这是让我们实现的是一个 大小固定的循环队列
正常的大小固定的队列如果满了就不能插入了
而这里所说的循环队列 是队尾和队头连在一起的
所以我们首先想到的就是 利用链表实现循环队列
链表实现分析
如下图:
刚开始head和tail都指向一个头!
这种结构下
- 插入数据只需要把数据放到tail节点,然后tail向后走
如图:push 1 2 3
- pop数据 只需要让head走向下一个,数据清除或者不清楚无所谓,反正可以被替换,
如图:pop pop
注意节点不需要释放!
而如果继续插入数据:push 4 5 6 7
可以看到此时已经满了!
但是,大家看一下我们设计的这个有没有什么缺陷呢?
!对! 我们可以看到!队列什么时候满呢?
head==tail的时候满
那么什么时候为空呢?
head==tail的时候为空!
所以! 这里判断空和满是有问题的!
那么解决方法是什么呢?
- 给一个size记录队列的大小,循环队列的节点数为k,每一次push的时候size++,pop时size–当
head==tail
时,如果size为k说明已经满了,如果size为0 则说明为空 - 给一个flag 刚开始flag为0表示队列为空,如果
head==tail
了 flag置为1,表示已经满了,当再pop的时候,就把flag改成0表示未满 - 比较官方的做法:
我们直接开辟k+1个链表节点,其中有一个节点不存储有效数据
判满的条件就是tail的下一个为head
如图:push 4 5 6 7
只能插入4 5 6 到7的时候 tail->next==head
所以已经满了,无法插入!
通常来说 结构就是这样的:
但是这时候这个队列还有别的问题吗?
我们要实现 push pop 判空 判满 获取队头数据 获取队尾数据 等等…
我们可以发现,如果想要获取队尾数据 是比较麻烦的!!
因为我们的tail是下一个要push的位置而不是真正的队尾
所以 我们如果想要解决,必须找到tail的前一个
- 方法1: 双向链表
- 方法2:记录尾的同时还要记录尾的前一个
显然 都是麻烦事! 所以利用链表是不方便实现的
所以我们选择用数组实现
三、💥题解💥
我们利用数组实现
先简单分析一下:
对于一个数组,我们要实现循环队列,那么
因为队列是循环的,所以什么时候队列是满的呢?
这就和我们链表部分分析的一样了,有三种方法!
- flag标识
- size记录队列大小
- 多开辟一个空间 ✅
我们采取对数组多开辟一个空间的方法:开辟(k+1)个空间
下面是具体接口实现:
✨代码中都有详细注释哦!!✨
定义队列结构
typedef struct {int* a;//动态开辟数组int head;//队头int tail;//队尾int k;//队的大小,因为后面传参的时候不会再传 k 所以我们定义在结构体里面
} MyCircularQueue;
Create(创建队列)
我们以k=5为例
首先创建一个队列结构然后开辟出队列中大小为`k+1`的数组然后把结构中的head和tail初始化为0
如图:
判断是否为空
前面我们对链表实现的分析的时候
我们已经分析过了
当`head`==`tail`的时候,为空
只是这里的`head`和`tail`变成了下标而不是节点
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//判断是不是为空 只需要判断tail是不是等于headreturn obj->head==obj->tail;}
判断是不是满了
这里是稍微有点麻烦的
首先我们要知道,判断满的条件是tail
的下一个等于head
但是这是数组 !not 链表
如果是环形链表,他会自动实现很自然的循环
但是链表不一样
链表会走到一个边界,所以我们需要考虑tail
的下一个是谁?
我们定义一个next
来标识下一个
一般的tail
的下一个就是tail+1
,如下图
但是存在特殊情况:如果tail
已经是最后一个位置了,那么这时候其实他的下一个就是返回开头0
找到下一个?
1. 定义一个next=tail+1如果tail==k+1那么next就为02. 利用取模我们知道一共有k+1个空间所以下标的返回时 0~ k这时候 next=(tail+1)%(k+1)不管next是不是超过了数组的返回,结果都是正确的
代码:
bool myCircularQueueIsFull(MyCircularQueue* obj) {//判断是不是满了//一般是判断tail的下一个是不是 head//需要考虑tail的下一个是什么?int next=obj->tail+1;if(next==obj->k+1){next=0;}//next=(obj->tail+1)%(k+1);if(next==obj->head)return true;elsereturn false;
}
获取队头元素
队头其实就是`head`
所以只需要访问数组中的`head`位置处的元素就可以了
但是需要注意:如果队列为空,返回-1
int myCircularQueueFront(MyCircularQueue* obj) {//如果队列为空 返回-1if(myCircularQueueIsEmpty(obj)){return -1;}//队头就是 headreturn obj->a[obj->head];
}
获取队尾元素
我们可以看到tail表示的是下一个Push的位置
而如果我们想获得队尾元素
应该是获得tail的前一个元素
所以我们定义一个prev来找到tail的前一个元素
但是也会有特殊情况
如果是这种情况,也就是 tail
已经折回去了
tail
为0 prev
应该为5
怎么找到prev
呢?
注意 如果我们让tail
+k+1 ,tail
就变成了6
这时候tail
-1是不是就等于prev
了?
tail
为0实际上就说明了tail
已经走到数组最后一个位置的后一个了
细细剖析理解一下这里:
而我们再看正确的情况是不是满足呢?
显然 满足的!
这样 我们就有两种情况控制边界情况
1. if判断
2. 利用取模
具体看个人喜欢用那种,小编这里就用第一种啦(比较直观)
int myCircularQueueRear(MyCircularQueue* obj) {//首先判断是否为空if(myCircularQueueIsEmpty(obj)){return -1;}//如果不为空//找到tail的前一个int prev=obj->tail-1;if(obj->tail==0)prev=obj->k;return obj->a[prev];
}
push接口
我们开始以k=5为例,即开辟了一个大小为6的数组
正常情况下,我们push只需要把tail位置放入元素,然后tail++就可以了
(向后走一步)
如图 我们把一个空的队列 push 1 2 3 4
操作过程:
但是会存在特殊情况
如图:
这时候怎么push呢?tail已经走到末尾了!
- 直接控制:正常走的话tail+1,tail就变成了6
所以 如果tail==k+1 那么我们让tail=0就可以了! - 利用取模
因为数组的总空间就是k+1
所以如果我们tail等于6了,说明tail应该走到0
所以让tail%=(k+1),也就是 6%6==0
还有一个问题就是
什么时候push失败呢?
当满的时候会push 失败!
push代码:
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//首先判断是不是满了//如果满了 push失败--返回falseif(myCircularQueueIsFull(obj)){return false;}//如果不满 直接插入就可以了obj->a[obj->tail]=value;//然后tail需要移动!obj->tail++;//如果移动之后tail走到末尾了 tail返回到数组的最开始if(obj->tail==obj->k+1){obj->tail=0;}return true;
}
pop接口
我们来看一个例子
如果操作为 pop pop
那么 head就需要往前走两步,从而实现删除的效果
但是如果继续pop
操作: pop pop
可以看到,此时队列已经空了!
此时继续pop就返回false(失败)
正常情况下pop只需要让head向后走,就可以了
因为前面的数据可以随意被覆盖就相当于被删了
但是也会有特殊情况,即当head走到边界
此时如果继续pop head++就变成了6
但是head应该返回到数组的头部0
所以 解决方法依旧有两个:
- 如果head==k+1
那么 head变成0 - 取模:如果head++之后变成6
那么head=head%(k+1)
代码:
bool myCircularQueueDeQueue(MyCircularQueue* obj) {//如果 队列已经空空了 就返回falseif(myCircularQueueIsEmpty(obj)){return false;}//如果队列不为空obj->head++;if(obj->head==obj->k+1){obj->head=0;}return true;
}
销毁
销毁就很简单了
只需要把结构销毁就可以了
注意:销毁结构之前,需要把结构中malloc的动态数组释放
否则容易造成内存泄漏!!
void myCircularQueueFree(MyCircularQueue* obj) {//首先释放数组空间free(obj->a);//然后释放队列free(obj);
}
总结:这道题还是比较麻烦的!
很多细节:比如边界 需要我们考虑全面!
下面是总代码供参考!
✏️总代码✏️
//使用数组实现typedef struct {int* a;//动态开辟数组int head;//队头int tail;//队尾int k;//队的大小,因为后面传参的时候不会再传k 所以我们定义在结构体里面
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->a=(int*)malloc(sizeof(int)*(k+1));obj->k=k;obj->head=obj->tail=0;return obj;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//判断是不是为空 只需要判断tail是不是等于headreturn obj->head==obj->tail;}bool myCircularQueueIsFull(MyCircularQueue* obj) {//判断是不是满了//一般是判断tail的下一个是不是 head//需要考虑tail的下一个是什么?int next=obj->tail+1;if(next==obj->k+1){next=0;}//next=(obj->tail+1)%(k+1);if(next==obj->head)return true;elsereturn false;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//首先判断是不是满了//如果满了 push失败--返回falseif(myCircularQueueIsFull(obj)){return false;}//如果不满 直接插入就可以了obj->a[obj->tail]=value;//然后tail需要移动!obj->tail++;//如果移动之后tail走到末尾了 tail返回到数组的最开始if(obj->tail==obj->k+1){obj->tail=0;}return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {//如果 队列已经空空了 就返回falseif(myCircularQueueIsEmpty(obj)){return false;}//如果队列不为空obj->head++;if(obj->head==obj->k+1){obj->head=0;}return true;
}int myCircularQueueFront(MyCircularQueue* obj) {//如果队列为空 返回-1if(myCircularQueueIsEmpty(obj)){return -1;}//队头就是 headreturn obj->a[obj->head];
}int myCircularQueueRear(MyCircularQueue* obj) {//首先判断是否为空if(myCircularQueueIsEmpty(obj)){return -1;}//如果不为空//找到tail的前一个int prev=obj->tail-1;if(obj->tail==0)prev=obj->k;return obj->a[prev];
}void myCircularQueueFree(MyCircularQueue* obj) {//首先释放数组空间free(obj->a);//然后释放队列free(obj);
}
💥💥最后贴一个题 💥💥
这个题适合 LeetCode622.循环队列中的边界问题相关的
看一下你学废了吗
5.现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。
其队内有效长度为?(假设队头不存放数据)
A (rear - front + N) % N + 1
B (rear - front + N) % N
C ear - front) % (N + 1)
D (rear - front + N) % (N - 1)
✨感谢阅读~ ✨
❤️码字不易,给个赞吧~❤️
相关文章:
【LeetCode刷题之路】622.设计循环队列
LeetCode刷题记录 🌐 我的博客主页:iiiiiankor🎯 如果你觉得我的内容对你有帮助,不妨点个赞👍、留个评论✍,或者收藏⭐,让我们一起进步!📝 专栏系列:LeetCode…...
暂停一下,给Next.js项目配置一下ESLint(Next+tailwind项目)
前提 之前开自己的GitHub项目,想着不是团队项目,偷懒没有配置eslint,后面发现还是不行。eslint的存在可以帮助我们规范代码格式,同时 ctrl s保存立即调整代码格式是真的很爽。 除此之外,团队使用eslint也是好处颇多…...
Windows系统磁盘与分区之详解(Detailed Explanation of Windows System Disks and Partitions)
Windows系统磁盘与分区知识详解 在日常使用Windows操作系统的过程中,我们常常会接触到磁盘管理,磁盘分区等操作.然而,许多人可能并不完全理解磁盘和分区的运作原理以及如何高效管理它们. 本篇文章将探讨Windows系统中关于磁盘和分区的各种知识,帮助大家更好地理解磁盘以及分区…...
顺序表的使用,对数据的增删改查
主函数: 3.c #include "3.h"//头文件调用 SqlListptr sql_cerate()//创建顺序表函数 {SqlListptr ptr(SqlListptr)malloc(sizeof(SqlList));//在堆区申请连续的空间if(NULLptr){printf("创建失败\n");return NULL;//如果没有申请成功ÿ…...
XDMA与FPGA:高效数据传输的艺术
XDMA与FPGA:高效数据传输的艺术 引言 在现代计算系统中,数据传输的效率直接影响系统的整体性能。特别是在涉及到高速数据处理的领域,如高性能计算(HPC)、实时视频处理和大数据分析等,如何高效地在主机与F…...
#思科模拟器通过服务配置保障无线网络安全Radius
演示拓扑图: 搭建拓扑时要注意: 只能连接它的Ethernet接口,不然会不通 MAC地址绑定 要求 :通过配置MAC地址过滤禁止非内部员工连接WiFi 打开无线路由器GUI界面,点开下图页面,配置路由器无线网络MAC地址过…...
浅谈Python库之pillow
一、pillow的介绍 Pillow是Python Imaging Library (PIL) 的一个分支,它是一个强大的图像处理库,用于打开、操作和保存许多不同图像文件格式。Pillow提供了广泛的文件格式支持、强大的图像处理能力和广泛的文件格式兼容性。它是PIL的一个友好的分支&…...
Android通过okhttp下载文件(本文案例 下载mp4到本地,并更新到相册)
使用步骤分为两步 第一步导入 okhttp3 依赖 第二步调用本文提供的 utils 第一步这里不做说明了,直接提供第二步复制即用 DownloadUtil 中 download 为下载文件 参数说明 这里主要看你把 destFileName 下载文件名称定义为什么后缀,比如我定义为 .mp4 下…...
计算机网络从诞生之初到至今的发展历程
前言 "上网",相信大家对这个动词已经不再陌生,网 通常指的是网络;在 2024 年的今天,网络已经渗透到了每个人的生活中,成为其不可或缺的一部分;你此时此刻在看到我的博客,就是通过网络…...
Kudu 源码编译-aarch架构 1.17.1版本
跟着官方文档编译 第一个问题:在make阶段时会报的问题: kudu/src/kudu/util/block_bloom_filter.cc:210:3: error: ‘vst1q_u32_x2’ was not declared in this scope kudu/src/kudu/util/block_bloom_filter.cc:436:5: error: ‘vst1q_u8_x2’ was no…...
SEC_ASA 第二天作业
拓扑 按照拓扑图配置 NTP,Server端为 Outside路由器,Client端为 ASA,两个设备的 NTP传输使用MD5做校验。(安全 V4 LAB考点) 提示:Outside路由器作为 Server端要配置好正确的时间和时区,ASA防…...
操作系统(5)进程
一、定义与特点 定义:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 特点: 动态性:进程是动态创建的,有它自身的生命周期,…...
6_Sass 选择器函数 --[CSS预处理]
Sass 提供了一系列的选择器函数,用于操作和组合CSS选择器。这些函数可以帮助你更灵活地创建样式规则,并且可以减少重复代码。以下是几个常用的选择器函数及其用法: 1. selector-append($selector1, $selector2...) selector-append($select…...
考研数学【线性代数基础box(数二)】
本文是对数学二线性代数基础进行总结,一些及极其简单的被省略了,代数的概念稀碎,不如高数关联性高,所以本文仅供参考,做题请从中筛选! 本文为初稿,后面会根据刷题和自己的理解继续更新 第一章…...
ModbusTcp获取数据
ModbusTcp获取数据 记录一个用 pymodbus 库来获取数据的代码。 注意: 1.读取寄存器地址是16进制的。2.大小端转换通过代码知道原理。读取数据时,切记频率别太高,否则会出现连接被关闭问题。 from pymodbus.client.sync import ModbusTcpCli…...
java 知识点:注解及使用
注解 大多数时候,我们会使用注解,而不是自定义注解。注解给谁用?编译器 、给解析程序用注解不是程序的一部分,可以理解为注解就是一个标签 主要的作用有以下四方面: 生成文档,通过代码里标识的元数据生成…...
AI预测体彩排3采取888=3策略+和值012路+胆码+通杀1码测试12月13日升级新模型预测第156弹
经过100多期的测试,当然有很多彩友也一直在观察我每天发的预测结果,得到了一个非常有价值的信息,那就是9码定位的命中率非常高,已到达90%的命中率,这给喜欢打私菜的朋友提供了极高价值的预测结果~当然了,大…...
faiss数据库检索不稳定
faiss数据检索不稳定 def build_faiss_index(embeddings_vector):dim np.shape(embeddings_vector)[-1]index faiss.index_factory(dim, HNSW64, faiss.METRIC_INNER_PRODUCT)index.add(embeddings_vector)return index这个代码不稳定,构建的索引召回结果可能会不…...
Vue技术中参数传递:Props与事件的实践指南
在Vue.js中,组件间的参数传递是构建动态和交互式应用的核心。本文将深入探讨如何通过Props和事件($emit)在Vue组件间进行参数传递,并提供代码示例。 Props传递数据 Props是Vue中组件间传递数据的一种方式,它允许父组…...
C++【基础】 ---- 快速入门 C++
文章目录 前言一、有关 const 区分二、有关命名空间三、有关输入和输出四、有关缺省参数四、函数重载总结 前言 本篇文章笔者将会对 C 这么语言中必须的基础部分进行简单讲解 , 同时也作为笔者自我复习使用, 这部分是初学C 的学者不可绕过的部分 , 希望学者认真理解 ,认真领会…...
Neo4j+Neovis+Vue3:前端连接数据库渲染
Neovis(github):https://github.com/neo4j-contrib/neovis.js Neovis配置文档:neovis.js (neo4j-contrib.github.io) 一、安装Neo4j 参考文章:neo4j下载安装配置步骤-CSDN博客 二、Neovis使用 1.npm引入 ?npm ins…...
React 18
文章目录 React 18自动批处理并发特性Suspense 组件增强新 HookscreateRoot API 替代 ReactDOM.renderStrict Mode严格模式服务器端渲染改进性能优化 React 18 React 18 引入了一系列新特性和改进,旨在提升性能、改善用户体验,并简化开发流程。以下是 R…...
Java:集合(List、Map、Set)
文章目录 1. Collection集合1-1. 迭代器遍历方式1-2. 通过for循环进行遍历1-3. forEach遍历 2. List集合2-1. ArrayList底层实现原理2-2. LinkedList底层实现原理 3. Set集合3-1. HashSet 底层实现3-2. LinkedHashSet 底层实现3-3. TreeSet 4. Collection集合->总结5. Map集…...
使用秘钥登录服务器
在我们测试或生产环境中,为了服务器安全性,有时可能需要以 SSH 密钥的方式登录服务器,接下来,将演示如何通过 SSH 私钥的方式来远程服务器。 一、远程服务器生成密钥对 1、首先在目标远程服务器下生成 SSH 密钥对 ssh-keygen然…...
BFS算法题
目录 1.BFS 2.树里的宽搜 题目一——429. N 叉树的层序遍历 - 力扣(LeetCode) 题目二——103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode) 题目三——662. 二叉树最大宽度 - 力扣(LeetCode) 题目四——…...
网络应用技术 实验八:防火墙实现访问控制(华为ensp)
目录 一、实验简介 二、实验目的 三、实验需求 四、实验拓扑 五、实验步骤 1、设计全网 IP 地址 2、设计防火墙安全策略 3、在 eNSP 中部署园区网 4、配置用户主机地址 5、配置网络设备 配置交换机SW-1~SW-5 配置路由交换机RS-1~RS-5 配置路由器R-1~R-3 6、配置仿…...
嵌入式现状、机遇、挑战与展望
在当今数字化浪潮中,嵌入式系统宛如一颗璀璨的明珠,熠熠生辉,深刻地渗透到了我们生活的方方面面,成为推动现代科技进步不可或缺的关键力量。从智能家居的便捷控制,到工业生产的精准运作,再到汽车的智能驾驶…...
天通卫星卡通知短信模板
文章目录 引言I 阿里云新增短信模板短信模板通知短信变量规范计费规则: 短信长度不超过70个字,按照1条短信计费;II 表设计III 实现方案引言 背景:天通卡适用于应急救灾、登山探险、海上通信、野外作业等需要稳定可靠通信的场景。 需求:天通卡充值成功通知 平台基于阿里云给…...
Unity WebGL 编译和打包说明(官方文档翻译校正)
目录 Unity WebGL 编译和打包说明WebGL 简介WebGL 浏览器兼容性 (WebGL Browser Compatibility)平台支持 (Platform Support)多线程支持限制多线程支持的因素安装 Unity Hub 并添加所需模块WebGL 开发WebGL Player 设置Resolution and PresentationResolutionWebGL TemplateSpl…...
题解 - 取数排列
题目描述 取1到N共N个连续的数字(1≤N≤9),组成每位数不重复的所有可能的N位数,按从小到大的顺序进行编号。当输入一个编号M时,就能打印出与该编号对应的那个N位数。例如,当N=3时,可…...
溧阳网站建设/seo页面排名优化
Seata实现熔断与限流一、分布式事务问题二、Seata简介三、Seata-Server安装四、订单/库存/账户业务数据库准备1、创建业务数据库2、按业务数据库创建表3、按业务数据库创建对应的回滚日记表五、订单/库存/账户业务微服务准备1、订单业务微服务Module2、库存业务微服务Module3、…...
花钱做网站注意些什么/吸引人的软文标题
自己擅长的,不是自己喜欢的,这种事很常见。明熹宗朱由校是狂热的木工活爱好者,爱因斯坦对小提琴比相对论还有信心,象棋大师杨官麟下的围棋比象棋多,围棋国手聂卫平打桥牌更是废寝忘食。 钱钟书在《窗》中有个调侃&…...
站长seo工具/网店运营公司
模型—视图—控制器(MVC)架构模式将一个应用程序分解为三个主要的组件:模型、视图和控制器。ASP.NET MVC framework为创建基于MVC的Web应用程序提供了一种ASP.NET Web Forms模式的替代形式。ASP.NET MVC framework是一个轻量的、高度可测试的…...
装修公司网站如何做网络推广/如何进行网站推广
在我之前的一篇文章中已经介绍了一种解密HTTPS流量的一种方法,大致方法就是客户端手动信任中间人,然后中间人重新封包SSL流量。文章地址: http://professor.blog.51cto.com/996189/1746183 ---------------------------------------------…...
专门做钣金的网站/昆山网站建设公司
删除算法相当的繁琐和复杂,且容易出错。 原则上,每次按键都可以当做一个独立的过程,对当前的按键序列进行运算,然而,由于有些结果是在按键过程中产生的,不宜每次按键都重复进行,因而需要善加利用…...
wordpress设计标题栏/企业查询信息平台
我们都知道现在大数据存储用的基本都是 Hdfs ,但在 Hadoop 诞生之前,我们都是如何存储大量数据的呢?这次我们不聊技术架构什么的,而是从技术演化的角度来看看 Hadoop Hdfs。 我们先来思考两个问题。 在 Hdfs 出现以前,…...