好题分享(2023.11.12——2023.11.18)

news2024/9/21 14:41:32

目录

前情回顾:

 前言:

题目一:《有效括号》

思路:

总结:

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

思路:

总结:

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

思路:

总结 :

总结:


 

 

前情回顾:

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

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

《链表中倒数第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.coloradmin.cn/o/1238186.html

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

相关文章

验证码 | 可视化一键管控各场景下的风险数据

目录 查看今日验证数据 查看未来趋势数据 验证码作为人机交互界面经常出现的关键要素&#xff0c;是身份核验、防范风险、数据反爬的重要组成部分&#xff0c;广泛应用网站、App上&#xff0c;在注册、登录、交易、交互等各类场景中发挥着巨大作用&#xff0c;具有真人识别、身…

C#winfrom端屏幕截图功能的简单实现(修改了屏幕的缩放比例后,截图功能异常,慎用!!!)

文章目录 1 主要文件1.1 FrmScreenShot.cs1.2 FrmScreenShot.Designer.cs1.1 Utility.cs 在发现有一款播放软件禁止截图功能后&#xff0c;使用了其他的截图工具发现都会被播放软件禁用掉截图功能&#xff0c;想了下试着自己做一个截图工具&#xff0c;也可以方便将截图工具添加…

【追求卓越01】数据结构--数组

引导 这一章节开始&#xff0c;正式进入数据结构与算法的学习过程中。由简到难&#xff0c;先开始学习最基础的数据结构--数组。 我相信对于数组&#xff0c;大家肯定是不陌生&#xff0c;因为数组在大多数的语言中都有&#xff0c;也是大家在编程中常常会接触到的。我不会说数…

文心大模型商业化领跑,百度在自我颠覆中重构生长力

随着科技巨头竞逐AI大模型&#xff0c;人工智能技术成为今年最受瞩目的新技术。但是&#xff0c;AI大模型的创新之路&#xff0c;还缺少一个足够有力的商业化答案。 作为全球最先发布大模型的互联网大厂&#xff0c;百度能否加速大模型的应用落地&#xff0c;以及文心大模型能…

【23真题】劝退211!今年突变3门课!

今天分享的是23年云南大学847&#xff08;原827&#xff09;的考研试题及解析。同时考SSDSP的院校做一个少一个&#xff0c;珍惜&#xff01;同时考三门课的院校&#xff0c;复习压力极大&#xff0c;但是也会帮大家劝退很多人&#xff0c;有利有弊&#xff0c;请自行分析~ 本…

微信小程序开发者工具] ? Enable IDE Service (y/N) ESC[27DESC[27C

在HBuilder运行微信小程序开发者工具报错 如何解决 打开微信小程序开发者工具打开设置--->安全设置--->服务器端口选择打开就可以啦

短时傅里叶变换函数编写

文章目录 傅里叶变换与短时傅里叶变换什么是窗&#xff1f;自己对手实现短时傅里叶变换 傅里叶变换与短时傅里叶变换 在了解短时傅里叶变换之前&#xff0c;首先要知道是什么是傅里叶变换&#xff08; fourier transformation&#xff0c;FT&#xff09;&#xff0c;傅里叶变换…

从 PUGC 到 SGC,普通店员也能用 AI 运营「粉丝群」

同一种文案风格反复使用&#xff0c;商品展示图也单调雷同&#xff0c;要直播时就直接「扔」个链接&#xff0c;社群、朋友圈这些品牌的私域重地有时极易被忽视&#xff0c;而变得千篇一律、简单粗暴。 但是&#xff0c;以内容驱动业务增长&#xff0c;已经成为越来越多品牌在做…

【EI会议征稿】第五届人工智能、网络与信息技术国际学术会议(AINIT 2024)

第五届人工智能、网络与信息技术国际学术会议&#xff08;AINIT 2024&#xff09; 2024 5th International Seminar on Artificial Intelligence, Networking and Information Technology 第五届人工智能、网络与信息技术国际学术会议&#xff08;AINIT 2024&#xff09;将于…

浅析教学型数控车床使用案例

教学型数控车床是一种专为教学和培训设计的机床&#xff0c;它具有小型化、高精度和灵活性的特点&#xff0c;可以作为学校和技术学院的培训机器。下面是一个使用案例&#xff0c;以展示教学型数控车床在教学实训中的应用。 案例背景&#xff1a; 某职业技术学院的机械工程专业…

Java计算时间差,距结束还有几天几小时几分钟

文章目录 1、写法2、备份3、LocalDate、LocalDateTime、Date、String互转 1、写法 //静态方法&#xff0c;传入年月日时分秒 LocalDateTime startTime LocalDateTime.of(2023, 11, 22, 15, 09, 59); LocalDateTime endTime LocalDateTime.of(2023, 11, 30, 0, 0, 0); //计算…

2023.11.22 -数据仓库

目录 https://blog.csdn.net/m0_49956154/article/details/134320307?spm1001.2014.3001.5501 1经典传统数仓架构 2离线大数据数仓架构 3数据仓库三层 数据运营层,源数据层&#xff08;ODS&#xff09;&#xff08;Operational Data Store&#xff09; 数据仓库层&#…

想打造私域流量帝国?先解决这4个难题!

一、谁是你的目标用户 1. 清晰界定目标用户&#xff1a;确定你的产品或服务主要面向的用户群体&#xff0c;如年龄段、性别、职业等特征。 2. 确定最有购买力的用户群体&#xff1a;分析哪个用户群体在购买你的产品或服务时更容易乐于支付&#xff0c;并将其作为重点关注对象。…

程序的执行原理(下)

文章目录 系统的硬件组成总线I/0设备主存处理器程序计数器&#xff08;PC&#xff09;加载:存储:操作:跳转: 运行 hello 程序读入寄存器&#xff0c;再把它存放到内存从磁盘加载程序到主存处理器执行程序并显示 参考 系统的硬件组成 总线 贯穿整个系统的是一组电子管道&#…

Java爬虫框架下代理使用中的TCP连接池问题及解决方案

引言 当使用Java爬虫框架进行代理爬取时&#xff0c;可能会遇到TCP连接池问题&#xff0c;导致"java.net.BindException: Cannot assign requested address"等错误。本文将介绍如何以爬取小红书为案例&#xff0c;解决Java爬虫框架中代理使用中的TCP连接池问题&…

连线鑫云:企业级存储设备制造商!

我们在今年的双11专场直播中&#xff0c;有幸邀请到了鑫云存储的嘉宾与我们连线&#xff0c;为大家作了一场精彩的分享。 这里&#xff0c;首先感谢鑫云存储对水经注的大力支持&#xff01; 现在&#xff0c;我们将嘉宾分享的内容进行简单整理&#xff0c;并以图文的方式与大家…

如何隐藏自己的代码(很酷)

1.引入 幻想当我们成为一名优秀的程序员&#xff0c;有着各大公司想要买我们的代码&#xff0c;但我们并不想要让他们知道我们代码的实现&#xff0c;毕竟一复制便可以解决&#xff0c;这里我们希望有一种方法可以把我们的核心代码给隐藏掉&#xff0c;那我们又应该怎么去实现呢…

计算3个点的6种分布在平面上的占比

假设平面的尺寸是6*6&#xff0c;用11的方式构造2&#xff0c;在用21的方式构造3 2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 1 2 2 3 3 3 x 3 3 2 2 2 1 2 2 2 2 2 1 2 2 在平面上有一个点x&#xff0c;11的操作吧平面分成了3部分2a1&#xff0c;2a…

【鸿蒙应用ArkTS开发系列】- 云开发入门实战二 实现城市多级联动Demo(上)

目录 概述 云数据库开发 一、创建云数据库的对象类型。 二、预置数据&#xff08;为对象类型添加数据条目&#xff09;。 三、部署云数据库 云函数实现业务逻辑 一、创建云函数 二、云函数目录讲解 三、创建resources目录 四、获取云端凭据 五、导出之前创建的元数据…

笔记58:Encoder-Decoder 架构

本地笔记地址&#xff1a;D:\work_file\&#xff08;4&#xff09;DeepLearning_Learning\03_个人笔记\3.循环神经网络\第9章&#xff1a;动手学深度学习~现代循环神经网络 a a a a a a a a a