当前位置: 首页 > news >正文

栈和队列OJ习题

目录

一. leetcode 20 有效的括号

思路(利用数据结构——栈)

代码实现

二. leetcode 225 用队列实现栈

思路

代码实现

三. leetcode 232 用栈实现队列

思路

代码实现

四. leetcode 622 环形队列

思路(用数组实现)

代码实现


一. leetcode 20 有效的括号

https://leetcode.cn/problems/valid-parentheses/description/

思路(利用数据结构——栈)

1、遍历字符串,遍历到左括号就入栈

2、遍历到右括号,就取栈顶,但是在取栈顶之前要先判断栈是否为空 ,若为空,说明前面肯定没有左括号与它匹配,返回 false

3、如果不为空,就可以比较遍历到的右括号是否与栈顶左括号匹配,如果不匹配,返回 false;如果匹配成功,就将左括号出栈,继续向后遍历字符串,直到遍历到字符串的末尾(即 '\0')

4、遍历完成之后,要判断栈是否为空,若为空,说明每个左括号都匹配成功,然后出栈了,如果栈不为空,说明仍有左括号在栈中未匹配并出栈,即这个字符串无效

代码实现

//定义栈的结构
typedef char STDataType;
typedef struct Stack
{STDataType* arr;int top;//指向栈顶的位置--刚好就是栈中有效数据的个数int capacity;
}ST;//初始化
void STInit(ST* ps)
{ps->arr = NULL;ps->capacity = ps->top = 0;
}//销毁
void STDesTory(ST* ps)
{if (ps->arr)free(ps->arr);ps->arr = NULL;ps->capacity = ps->top = 0;
}//入栈
void STPush(ST* ps, STDataType x)
{assert(ps);//判断空间是否足够if (ps->top == ps->capacity){//增容int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;STDataType* tmp = (STDataType*)realloc(ps->arr, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}//空间足够ps->arr[ps->top++] = x;
}//栈是否为空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}//出栈
void STPop(ST* ps)
{assert(!STEmpty(ps));ps->top--; 
}//取栈顶
STDataType STTop(ST* ps)
{assert(ps);return ps->arr[ps->top - 1];
}//---------------以上为栈结构的定义及一些常用方法----------------bool isValid(char* s) {ST st;STInit(&st);char* pi=s;while(*pi!='\0'){//左括号入栈if(*pi=='(' || *pi=='[' || *pi=='{'){STPush(&st,*pi);}else{//判断栈是否为空,不为空才能取栈顶if(STEmpty(&st)){STDesTory(&st);return false;}//右括号---取栈顶,比较,匹配出栈,不匹配直接返回falsechar top=STTop(&st);if((top=='(' && *pi !=')')|| (top=='[' && *pi !=']')|| (top=='{' && *pi !='}')){STDesTory(&st);return false;}//本次是匹配的,出栈STPop(&st);}pi++;}//判断栈是否为空,为空有效,非空无效//if(STEmpty(&st))// {//     STDataType(&st);//     return true;// }bool ret=STEmpty(&st) ? true :false;STDesTory(&st);return ret;
}

二. leetcode 225 用队列实现栈

https://leetcode.cn/problems/implement-stack-using-queues/description/

思路

  • 入栈:往不为空的队列中插入数据(两个都为空队列,随便选择一个即可,但是不能往两个队列都插入数据)
  • 出栈:将不为空队列的前 size-1 个数据依次插入到另一个队列中,再将其最后一个数据出队列
  • 取栈顶(不出数据):找不为空的队列,返回队尾数据
  • 判空:两个队列都为空,返回 true,有一个不为空即返回 false

代码实现

typedef int QDataType;
//定义队列节点结构
typedef struct QueueNode {QDataType data;struct QueueNode* next;
}QueueNode;//定义队列结构
typedef struct Queue {QueueNode* phead;//对头QueueNode* ptail;//队尾
//	int size;        //队列中有效数据个数
}Queue;//初始化
void QInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;
}//入队——队尾入
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//创建值为x的节点QueueNode* newnode =(QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;//队列为空if (pq->phead == NULL){pq->phead = pq->ptail = newnode;}else {pq->ptail->next = newnode;pq->ptail = pq->ptail->next;}
}//判断队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;//相等返回true,不相等返回false 
}//出队——队头出
void QueuePop(Queue* pq)
{//判断队列是否为空assert(!QueueEmpty(pq)); //队列中只有一个节点if (pq->phead == pq->ptail){pq->phead = pq->ptail = NULL;}else {QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}
}//取队头数据
QDataType QueueFront(Queue* pq)
{assert(!QueueEmpty(pq));return pq->phead->data;
}//取队尾数据
QDataType QueueBack(Queue* pq)
{assert(!QueueEmpty(pq));return pq->ptail->data;
}//队列有效元素个数
int QueueSize(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;int size = 0;while (pcur){size++;pcur = pcur->next;}return size; 
}//销毁
void QueueDestory(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = pq->ptail = NULL;
}//---------------------以上是队列的结构和常用方法---------------------------//两个队列实现一个栈
typedef struct {Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate() {MyStack* pst=(MyStack*)malloc(sizeof(MyStack));QInit(&pst->q1);QInit(&pst->q2);return pst;
}void myStackPush(MyStack* obj, int x) {//往不为空的队列中插入数据  if(!QueueEmpty(&obj->q1)){//q1QueuePush(&obj->q1,x);}else{//q2QueuePush(&obj->q2,x);}}int myStackPop(MyStack* obj) {//找不为空的队列Queue* emp=&obj->q1;Queue* noneEmp=&obj->q2;if(QueueEmpty(&obj->q2)){emp=&obj->q2;noneEmp=&obj->q1;}//不为空队列前size-1个数据挪到空队列while(QueueSize(noneEmp)>1){// //取队头// int front=QueueFront(&noneEmp);// //入另一个队列// QueuePush(&emp,front);//上面两步合并,取队头入另一个队列QueuePush(emp,QueueFront(noneEmp));//出队头QueuePop(noneEmp);}//不为空队列出数据int top =QueueFront(noneEmp);QueuePop(noneEmp);return top;
}int myStackTop(MyStack* obj) {//找不为空的队列,返回不为空队列的队尾数据if(!QueueEmpty(&obj->q1)){return QueueBack(&obj->q1);}else{return QueueBack(&obj->q2);}
}bool myStackEmpty(MyStack* obj) {//两个队列都为空return QueueEmpty(&obj->q1)&& QueueEmpty(&obj->q2);
}void myStackFree(MyStack* obj) {QueueDestory(&obj->q1);QueueDestory(&obj->q2);free(obj);obj=NULL;
}

三. leetcode 232 用栈实现队列

https://leetcode.cn/problems/implement-queue-using-stacks/description/

思路

  • 入队列:往 pushST 栈中直接插入数据
  • 出队列:若 popST 栈为空,要将pushST 栈中的所有数据依次插入到popST 栈中,然后出popST 栈顶;若popST 栈不为空,则直接出 popST 栈顶
  • 取队头:若 popST 栈为空,要将pushST 栈中的所有数据依次插入到popST 栈中,然后取popST 栈顶;若popST 栈不为空,则直接取 popST 栈顶
  • 判空:两个栈都为空,返回 true,有一个不为空即返回 false

代码实现

//定义栈的结构
typedef int STDataType;
typedef struct Stack
{STDataType* arr;int top;//指向栈顶的位置--刚好就是栈中有效数据的个数int capacity;
}ST;//初始化
void STInit(ST* ps)
{ps->arr = NULL;ps->capacity = ps->top = 0;
}//销毁
void STDesTory(ST* ps)
{if (ps->arr)free(ps->arr);ps->arr = NULL;ps->capacity = ps->top = 0;
}//入栈
void STPush(ST* ps, STDataType x)
{assert(ps);//判断空间是否足够if (ps->top == ps->capacity){//增容int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;STDataType* tmp = (STDataType*)realloc(ps->arr, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}//空间足够ps->arr[ps->top++] = x;
}//栈是否为空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}//出栈
void STPop(ST* ps)
{assert(!STEmpty(ps));ps->top--; 
}//取栈顶
STDataType STTop(ST* ps)
{assert(!STEmpty(ps));return ps->arr[ps->top - 1];
}//获取栈中有效元素个数
int STSize(ST* ps)
{assert(ps);return ps->top;
}//----------------以上是栈的结构定义和常见方法------------------typedef struct {ST pushST;ST popST;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* pq=(MyQueue*)malloc(sizeof(MyQueue));STInit(&pq->pushST);STInit(&pq->popST);return pq;
}//入队
void myQueuePush(MyQueue* obj, int x) {//往pushST中插入数据STPush(&obj->pushST,x);
}//出队
int myQueuePop(MyQueue* obj) {//popST为空---将pushST(不为空)所有数据导入到popSTif(STEmpty(&obj->popST)){while(!STEmpty(&obj->pushST)){//取栈顶,入栈,出栈STPush(&obj->popST,STTop(&obj->pushST));STPop(&obj->pushST);}}//popST不为空直接出STDataType top=STTop(&obj->popST); STPop(&obj->popST);return top;
}//取队头
int myQueuePeek(MyQueue* obj) {//popST为空---将pushST(不为空)所有数据导入到popSTif(STEmpty(&obj->popST)){while(!STEmpty(&obj->pushST)){//取栈顶,入栈,出栈STPush(&obj->popST,STTop(&obj->pushST));STPop(&obj->pushST);}}//popST不为空直接取数据STDataType top=STTop(&obj->popST); return top;
}bool myQueueEmpty(MyQueue* obj) {return STEmpty(&obj->pushST) && STEmpty(&obj->popST);
}void myQueueFree(MyQueue* obj) {STDesTory(&obj->pushST);STDesTory(&obj->popST);free(obj);obj=NULL;
}

四. leetcode 622 环形队列

https://leetcode.cn/problems/design-circular-queue/description/

环形队列的特点:

  • 队头删数据,队尾插数据
  • 给定固定的空间,使用过程中不可以扩容
  • 环形队列满了,不可以继续插入数据(即插入数据失败)

环形队列可以使用数组实现,也可以用循环链表实现,用数组比较简便,原因如下:

如果用链表,初始化时,有多少个数据,就要创建多少个节点,并且每个节点就有两个成员,将这些节点联系在一起;如果用数组的话,初始化时,有多少数据,直接申请多大的空间即可,所以初始化数组更简便。而且在进行遍历/插入/删除操作时,两者的没有太大的区别。综上,数组在结构上和初始化时更简便,所以用数组比较好。(感兴趣的同学可以自行用链表试一下)

思路(用数组实现)

假设 k == 4 时,往数组中插入4个数据,rear 想要回到头节点,我们可以将 rear % 4,这样rear就回到了队头,这时 front == rear,但是,队列为空时,front == rear。如何区分环形队列是空的还是满的?

我们可以在环形队列结构中增加一个计数器成员来保存队列中有效数据的个数。那如果不能在环形队列结构中额外增加计数器成员来保存有效数据个数呢?

虽然题目要求只能保存 k 个数据,但是没有要求这个环形队列只能是 k 个空间,所以我们可以多增加一个空间,这个空间不保存任何数据,申请 k+1 个空间,这样只是在环形队列的 arr 数组中浪费了一个空间。

代码实现

typedef struct {int* arr;int front;//队头int rear;//队尾int capacity;//循环队列的空间大小(即K)
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* pq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//申请k+1个空间pq->arr = (int*)malloc(sizeof(int)*(k+1));pq->front = pq->rear = 0;pq->capacity = k;return pq;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->rear;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->rear + 1)%(obj->capacity + 1) == obj->front;
}//向循环队列插入一个元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//判断是否满了if(myCircularQueueIsFull(obj)){return false;}//没有满obj->arr[obj->rear++] = value;//如果rear果越界obj->rear %= obj->capacity + 1;return true;
}//从循环队列中删除一个元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {//判断是否为空if(myCircularQueueIsEmpty(obj)){return false;}//非空,删除队头数据++obj->front;//如果front越界obj->front %= obj->capacity + 1;return true;
}//从队首获取元素
int myCircularQueueFront(MyCircularQueue* obj) {//判断是否为空if(myCircularQueueIsEmpty(obj)){return -1;}//不为空return obj->arr[obj->front];
}//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {//判断是否为空if(myCircularQueueIsEmpty(obj)){return -1;}//不为空int prev = obj->rear - 1;if(obj->rear == 0){prev = obj->capacity;}return obj->arr[prev];
}void myCircularQueueFree(MyCircularQueue* obj) {//看初始化时向操作系统要了那些空间if(obj->arr)free(obj->arr);free(obj);obj = NULL;
}

总结

栈与队列作为数据结构中的 “基础容器”,其 “先进后出(LIFO)” 与 “先进先出(FIFO)” 的核心特性,是解决诸多算法问题的关键逻辑支撑。本文通过经典题型拆解,系统梳理了栈和队列 OJ 习题的解题思路,旨在帮助读者从 “会做题” 过渡到 “懂原理、能迁移”。

如果大家在练习中发现新的解题角度,或是有没搞懂的知识点,欢迎在评论区留言讨论。后续我也会持续更新数据结构相关的 OJ 解析,咱们一起在刷题中夯实基础,稳步进阶!

http://www.dtcms.com/a/356467.html

相关文章:

  • 【物联网】关于 GATT (Generic Attribute Profile)基本概念与三种操作(Read / Write / Notify)的理解
  • 如何在mysql中执行创建数据库的脚本文件?
  • Spring Boot 使用 RestTemplate 调用 HTTPS 接口时报错:PKIX path building failed 解决方案
  • Linux下的网络编程SQLITE3详解
  • 神经语言学视角:脑科学与NLP深层分析技术的交叉融合
  • Java的CAS机制:无锁并发控制及其高频面试题
  • OpenCSG月度更新2025.8
  • 1 分钟 Maya 动画渲染要多久?5 天还是 5 小时
  • 基于Java、GeoTools与PostGIS的GeoJSON动态属性注入实战指南
  • 在 Go 项目的 DDD 分层架构中,Echo Web 框架及其 middleware 应该归属到哪一层?
  • mysql安全运维之安全模型与原则-构建坚不可摧的数据库防护体系
  • 自然语言提取PDF表格数据
  • 电影交流|基于SprinBoot+vue的电影交流平台小程序系统(源码+数据库+文档)
  • 在基于 Go 的 DDD 分层架构中,包含多个server的项目目录结构应如何组织?
  • LoraConfig target modules加入embed_tokens(64)
  • 设计模式-行为型模式-命令模式
  • Spring 微服务架构下的单元测试优化实践:从本地连接到真实开发数据库的集成测试
  • Qt节点编辑器设计与实现:动态编辑与任务流可视化(一)
  • WebStorm-在WebStorm中使用Git管理项目
  • 【WPF】WPF 自定义控件实战:从零打造一个可复用的 StatusIconTextButton (含避坑指南)
  • 循环高级(2)
  • 面试八股文之——JVM与并发编程/多线程
  • Azure、RDP、NTLM 均现高危漏洞,微软发布2025年8月安全更新
  • 【物联网】什么是 DHT11(数字温湿度传感器)?
  • C++ 编译和运行 LibCurl 动态库和静态库
  • SyncBack 备份同步软件: 使用 FTPS、SFTP 和 HTTPS 安全加密传输文件
  • 【2025 完美解决】Failed connect to github.com:443; Connection timed out
  • 网络编程(2)—多客户端交互
  • 跨境物流新引擎:亚马逊AGL空运服务赋能卖家全链路升级
  • Pycharm 登录 Github 失败