好题分享(2023.11.12——2023.11.18)

目录

前情回顾:

 前言:

题目一:《有效括号》

思路:

总结:

题目二:《用队列实现栈》

思路:

总结:

题目三:《用栈实现队列》 

思路:

总结 :

总结:


 

 

前情回顾:

我们在上一篇好题分析中,分析了以下几题:

《反转链表》《相交链表》《环形链表(一)》《环形链表(二)》《随机链表的复制》《合并两个有序链表》

《链表中倒数第K个节点》《链表分割》《链表的回文结构》

上一篇的好题分析的blog:

好题分享(2023.11.5——2023.11.11)-CSDN博客

 前言:

本次《好题分享》当中,我们主要熟悉我们刚刚所学的《栈和队列》这一部分内容。

通过三道Leecode题目使我们对于《栈和队列》能有一个更好的认识。

以下是我们需要解决的三道题目:

《有效括号》《用队列实现栈》《用栈实现队列》

 这三道题的代码量都会非常的长,那是由于我们现在处于初学阶段,没有办法使用一些高效的方法来解决这些题目,但是不用怕,因为我们不仅仅实现过《栈》也实现过《队列》。

对于《栈和队列》的讲解可以去访问我的上一篇blog

《栈和队列》的模拟实现(顺序栈) (链队列)-CSDN博客

里面有需要实现本次题目的代码,打开我的Gitee即可获取。

在做题目之前我们首先需要将我们实现好的《栈》或者《队列》的代码粘贴到题目最前面的位置。

那么现在我们就来动手实践以及讲解 


题目一:《有效括号》

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

 

typedef char STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;void STInit(ST* pst)
{pst->a = NULL;pst->capacity = 0;pst->top = -1;
}void STDestory(ST* pst)
{assert(pst);free(pst);pst = NULL;
}void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->capacity == pst->top || pst->top == -1){int newCapacity = (pst->capacity == 0) ? 4 : 2 * (pst->capacity);STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(ST)*newCapacity);if (tmp == NULL){perror("STPush -> realloc");exit(-1);}pst->a = tmp;pst->capacity = newCapacity;}pst->top++;pst->a[pst->top] = x;
}void STPop(ST* pst)
{assert(pst);pst->top--;
}STDataType STTop(ST* pst)
{assert(pst);return pst->a[pst->top];
}bool STEmpty(ST* pst)
{assert(pst);if (pst->top == -1){return true;}return false;
}int STSize(ST* pst)
{assert(pst);return (pst->top) + 1;
}void STPrint(ST* pst)
{assert(pst);while (pst->top != -1){printf("%d\n", STTop(pst));STPop(pst);}
}bool isValid(char* s) {ST st;STInit(&st);while(*s){if(*s == '[' || *s == '(' || *s == '{'){STPush(&st,*s);}else{if(STEmpty(&st)){return false;}else{char top = STTop(&st);STPop(&st);if((top == '(' && *s != ')')||(top == '{' && *s != '}')|| (top == '[' && *s != ']')){return false;}}}s++;}if(!STEmpty(&st)){return false;}return true;}

思路:

 

本题的思路就是利用《栈》的性质——先进后出

因为是匹配括号,我们不妨假设其本质就是一个《栈》。

我们先去遍历字符串,如果访问到左括号,例如

"{"                   "("                "["

就直接入栈。

而如果访问到右括号,我们就与栈顶的括号匹配,如果左右括号匹配成功就删除栈顶的括号,字符串继续遍历,直到遍历完成。

如图:

 

 

 栈顶的括号与s指向的括号相匹配

 

此时相匹配,则删除栈顶元素:

 

如此继续遍历。

 

此时s指向'\0'代表遍历结束,而如果《栈》为空,就代表着字符串为有效括号,就可以return true

总结:

1.创建《栈》

2.遍历字符串,左括号入《栈》

3.遍历到右括号,则于《栈》顶的左括号相匹配

4.当字符串遍历完后,《栈》为空则return true;

但是这里存在一个细节,需要去注意

例如,如果我们在遍历字符串时遍历到有括号时,可是《栈》中没有栈顶元素与之匹配,则直接返回false。

 

题目二:《用队列实现栈》

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

 

typedef int QDataType;typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int sz;
}Queue;void QueueInit(Queue* pq)
{pq->sz = 0;pq->phead = pq->ptail = NULL;
}void QueueDestroy(Queue* pq)
{assert(pq);assert(pq->phead);QNode* cur = pq->phead->next;while (cur){free(pq->phead);pq->phead = cur;cur = cur->next;}free(pq->phead);pq->phead = pq->ptail = cur = NULL;}void QueuePop(Queue* pq)
{assert(pq);if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QNode* tmp = pq->phead->next;free(pq->phead);pq->phead = tmp;}pq->sz--;
}void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("QueuePush -> malloc");exit(-1);}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->sz++;
}QDataType QueueFront(Queue* pq)
{assert(pq);return pq->phead->val;
}QDataType QueueBack(Queue* pq)
{assert(pq);return pq->ptail->val;
}bool QueueEmpty(Queue* pq)
{assert(pq);if (pq->phead == NULL){return true;}return false;
}int QueueSize(Queue* pq)
{return pq->sz;
}void QueuePrint(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){printf("%d->", cur->val);cur = cur->next;}printf("NULL\n");
}typedef struct {Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate() {MyStack* pst = (MyStack*)malloc(sizeof(MyStack));QueueInit(&pst->q1);QueueInit(&pst->q2);return pst;
}void myStackPush(MyStack* obj, int x) {if (QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2)){QueuePush(&obj->q1, x);}else{if (!QueueEmpty(&obj->q1)){QueuePush(&obj->q1, x);}else{QueuePush(&obj->q2, x);}}
}int myStackPop(MyStack* obj) {if (QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2)){return 0;}else{if (!QueueEmpty(&obj->q1)){int n = QueueSize(&obj->q1) - 1;while (n){int top = QueueFront(&obj->q1);QueuePush(&obj->q2, top);QueuePop(&obj->q1);n--;}int top = QueueFront(&obj->q1);QueuePop(&obj->q1);return top;}else{int n = QueueSize(&obj->q2) - 1;while (n){int top = QueueFront(&obj->q2);QueuePush(&obj->q1, top);QueuePop(&obj->q2);n--;}int top = QueueFront(&obj->q2);QueuePop(&obj->q2);return top;}}
}int myStackTop(MyStack* obj) {if (QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2)){return 0;}else{if (!QueueEmpty(&obj->q1)){return QueueBack(&obj->q1);}else{return QueueBack(&obj->q2);}}
}bool myStackEmpty(MyStack* obj) {if (!QueueEmpty(&obj->q1) || !QueueEmpty(&obj->q2)){return false;}return true;}void myStackFree(MyStack* obj) {if (!QueueEmpty(&obj->q1) && !QueueEmpty(&obj->q2)){if (!QueueEmpty(&obj->q1)){QueueDestroy(&obj->q1);}else{QueueDestroy(&obj->q2);}}
}/*** Your MyStack struct will be instantiated and called as such:* MyStack* obj = myStackCreate();* myStackPush(obj, x);* int param_2 = myStackPop(obj);* int param_3 = myStackTop(obj);* bool param_4 = myStackEmpty(obj);* myStackFree(obj);
*/

该题目的代码量会非常长,刚开始做题时是会产生恐惧,但是不用害怕,因只要我们了解了其中代码的秘密,我们就能迎刃而解了。

思路:

 由题意,就是让我们创建两个栈,然后通过两个栈之间的操作,完成一个队列的基本实现。

我们想要插入12345,那么对于栈来说

1就是《栈》底元素,5就是《栈》顶元素。

出栈也只能出5

但是对于队列而言呢?

队头是1,队尾是5

出队列也只能出1.

所以对于“出栈”就可以利用两个队列:

先让12345插入到队列1,即q1

再让q1中的各个元素一个个的进到队列q2中

 

 

如此不断循环

直到q1只剩一个元素,那个元素就是对应的“栈顶”。

我们将这个元素删除即可:

 

 

 最后则返回top:

以上就是“出栈”的函数实现,那么对于入栈来说,就是哪个队列不为空就插入到哪个队列中。

具体的代码还是好实现的。后续的函数我也不做过多的赘述。

总结:

对于这道题我们讲解关于“出栈”函数的实现就可以解决大部分问题。

但是这道题的自定义数据类型可能会有人绕不清楚,接下来我画一张图大家就可以理解了:

 

我们在上一篇blog也讲过,创建一个结构体用来保存头指针和尾指针对象,可以大大提高传输效率,也可以使人理解透彻!

 

题目三:《用栈实现队列》 

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

typedef int STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;void STInit(ST* pst)
{assert(pst);pst->a = NULL;pst->capacity = 0;pst->top = -1;
}void STDestory(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = -1;pst->capacity = 0;
}void STPush(ST* pst, STDataType x)
{assert(pst);int newcapacity = (pst->capacity == 0) ? 4 : 2 * (pst->capacity);STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);if (tmp == NULL){perror("STPush -> realloc");exit(-1);}pst->a = tmp;pst->capacity = newcapacity;pst->top++;pst->a[pst->top] = x;}void STPop(ST* pst)
{assert(pst);if (pst->top != -1){pst->top--;}
}STDataType STTop(ST* pst)
{assert(pst);if (pst->top != -1){return pst->a[pst->top];}return -1;
}bool STEmpty(ST* pst)
{assert(pst);if (pst->top == -1){return true;}return false;
}int STSize(ST* pst)
{assert(pst);return pst->top + 1;
}void STPrint(ST* pst)
{assert(pst);for (int i = 0; i <= pst->top; i++){printf("%d  ", pst->a[i]);}
}typedef struct {ST SPush;ST SPop;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));STInit(&obj->SPush);STInit(&obj->SPop);return obj;
}void myQueuePush(MyQueue* obj, int x) {STPush(&obj->SPush,x);
}int myQueuePop(MyQueue* obj) {int front = myQueuePeek(obj);STPop(&obj->SPop);return front;
}int myQueuePeek(MyQueue* obj) {if(STEmpty(&obj->SPop)){while(!STEmpty(&obj->SPush)){STPush(&obj->SPop,STTop(&obj->SPush));STPop(&obj->SPush);}}return STTop(&obj->SPop);
}bool myQueueEmpty(MyQueue* obj) {if(STEmpty(&obj->SPush) && STEmpty(&obj->SPop)){return true;}return false;
}void myQueueFree(MyQueue* obj) {STDestory(&obj->SPop);STDestory(&obj->SPush);free(obj);
}/*** Your MyQueue struct will be instantiated and called as such:* MyQueue* obj = myQueueCreate();* myQueuePush(obj, x);* int param_2 = myQueuePop(obj);* int param_3 = myQueuePeek(obj);* bool param_4 = myQueueEmpty(obj);* myQueueFree(obj);
*/

本题的代码与上题一样,先将实现栈的函数粘贴到该题目中。

思路:

 我们还是先来讲讲“出队列”这个思路。

“出队列”秉持一个原则,就是先进先出

而出缺是后进先出,所以我们不得不继续用到两个栈。

但是这里我们不同于上一道题,我们必须定义两个栈

即一个栈只能入数据,一个栈是用来出数据的。

 比如我还是将12345入栈。

如果是队列的话,只能实现先进先出,即将1删除。

所以我们可以借鉴上题那样,先将SPush里面的所以元素移到SPop中 :

这样一来,我们只需要删除SPop的栈顶元素即可。

如果我们想要继续输入数据,也不需要将SPop里面的数据再倒入SPush中,只需要再SPush里面继续添加新数据。

反正,只要SPop这个栈里有数据,就先删除栈顶的,而对于添加数据,只需要向SPush里面添加即可。

 

当删完SPop后如果还想删数据,则继续将SPush里面的数据倒入SPop即可。

 

总结 :

当然还是会有人对数据类型不是很理解,我还是画个图给大家观看:

 

 

总结:

 本文主要以巩固《栈和队列》为主,从此以后的好题分析,我们主要给大家讲解最关键思路,以及部分重难点函数的实现。

同学们下来可以自己动手尝试编写编写。

记住

“坐而言不如起而行!”

Aciton speak louder than words!

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

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

相关文章

【Vue】生命周期一文详解

目录 前言 生命周期 钩子函数使用方法 ​编辑 周期-----创建阶段 创建阶段做了些什么事 该阶段可以干什么 周期----挂载阶段 挂载阶段做了什么事 该阶段适合干什么 周期----更新阶段 更新阶段做了什么事 该阶段适合做什么 周期----销毁阶段 销毁阶段做了什么事 …

MCU 的 TOP 15 图形GUI库:选择最适合你的图形用户界面(一)

在嵌入式系统开发中&#xff0c;选择一个合适的图形用户界面&#xff08;GUI&#xff09;库是至关重要的。在屏幕上显示的时候&#xff0c;使用现成的图形库&#xff0c;这样开发人员就不需要弄清楚底层任务&#xff0c;例如如何绘制像素、线条、形状&#xff0c;如果再高级一点…

图片上的水印怎么去除掉?水印云提供一键解决方案!

在快节奏的数字世界中&#xff0c;图像和视频现已成为我们生活的重要组成部分。从热门名人到热门电视节目&#xff0c;在线内容每天都会引发争论&#xff0c;吸引了大量观众。对于铁杆粉丝来说&#xff0c;每一条新内容都是捕捉难忘时刻的机会——无论是名人富有感染力的微笑、…

Linux进程理解(冯诺依曼体系结构,操作系统,进程概念和基本操作)

Linux进程理解[冯诺依曼体系结构,操作系统,进程概念和基本操作] 一.冯诺依曼体系结构1.冯诺依曼体系结构的说明2.冯诺依曼体系结构的价值1.冯诺依曼之前的计算机的局限2.为什么在计算机体系结构当中要存在内存? 二.操作系统1.什么是操作系统2.操作系统如何进行管理3.为什么要有…

K8S部署mongodb-sharded-cluster(7.0.2)副本分片

添加源 helm repo add bitnami https://charts.bitnami.com/bitnami指定版本拉取 helm pull --repo https://charts.bitnami.com/bitnami mongodb-sharded --version 7.0.5安装时选择SCRAM-SHA-1默认是SCRAM-SHA-256 helm install -n prod mymongodb mongodb-sharded --value…

react大文件上传

目录 大文件上传优点&#xff1a; 大文件上传缺点: 大文件上传原理&#xff1a; 为什么要用md5 实现流程&#xff1a; 部分代码1&#xff1a; 部分代码2&#xff1a;​ 大文件上传优点&#xff1a; 文件太大分片上传能加快上传速度,提高用户体验能断点续传 如果上次上传失败…

vue2中的props属性

vue2中的props属性 props传递&使用 调用子组件是创建子组件的实例 传递属性&#xff1a;:a"a"&#xff0c;非字符串都用v-bind created: 属性 状态 computed watch都处理好了 会被挂载到实例上get/set劫持&#xff1a;get获取最新&#xff0c;set目的抛出错误 修…

uniapp实现表单弹窗

uni.showModal({title: 删除账户,confirmColor:#3A3A3A,cancelColor:#999999,confirmText:确定,editable:true,//显示content:请输入“delete”删除账户,success: function (res) {console.log(res)if(res.confirm){if(res.contentdelete){console.log(123123123213)uni.setSto…

如何让Python2与Python3共存

安装 首先分别安装Py2和Py3&#xff0c;我都安装到C盘根目录里了&#xff0c;然后分别将Py2和Py3都配置到系统环境变量中去&#xff1a;C:\Python36\Scripts\;C:\Python36\;C:\Python27\;C:\Python27\Scripts; 配置 修改两个版本的可执行文件名字 验证 重新配置一下pip …

前端数组方法汇总集锦

前言 数组主要使用场景有&#xff1a; 存储和处理数据&#xff1a;数组是一种有序的数据结构&#xff0c;可以用来存储和处理多个相关的数据。在前端开发中&#xff0c;我们经常使用数组来存储和处理列表、表格、选项等数据。 循环和遍历&#xff1a;数组提供了循环和遍历的功能…

柱形图:制作图表时,有时会遇到柱形图系列没有居中显示,例如:

问题描述 制作图表时&#xff0c;有时会遇到柱形图系列没有居中显示&#xff0c;例如&#xff1a; 原因分析 柱形图的「分类」和「系列名」均选择了「地区」&#xff0c;导致分类下存在不同的系列&#xff0c;那么当前分类下没有的系列就会存在「空白占位」。 解决方案 此时…

vue diff算法原理以及v2v3的区别

diff算法简介 diff算法的目的是为了找到哪些节点发生了变化&#xff0c;哪些节点没有发生变化可以复用。如果用最传统的diff算法&#xff0c;如下图所示&#xff0c;每个节点都要遍历另一棵树上的所有节点做比较&#xff0c;这就是o(n^2)的复杂度&#xff0c;加上更新节点时的…