栈和队列OJ题

news2025/1/19 23:17:06

有效括号问题:

题目描述:

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

思路:

解决此类问题,传统的暴力遍历法已经不再适用了,暴力遍历无法保证括号的匹配顺序,仅能通过统计左右括号的数量进行比较判断,但即使是左右括号数量相等,也不一定是有效的,如:“( [ { ] ) }”,虽然左右括号数量相同,但是它们的顺序不对,不能相互匹配,所以也是无效的,因此,暴力遍历的方法是不行的。

此时我们应该从问题本身出发,思考一下括号匹配的本质是什么?

我们知道一个合法的括号包括两部分:左括号和右括号,括号匹配就是匹配左右括号,并且每次匹配时都是相邻最近的两个左右括号进行匹配。因此,我们可以创建一个数组用来储存左括号,依次遍历,每出现一次左括号就存进这个数组中,每次出现右括号时,将它与数组中最后一个左括号进行匹配,若匹配成功,则删除数组最后一个左括号,再从下一个开始遍历;若匹配不成功,则说明是非法括号字符串,直接退出程序……直至遍历完括号字符串或者中间出现不匹配的情况直接退出。若正常遍历完括号字符串,再看数组中是否为空,若为空,说明该括号字符串中所有左右括号都匹配成功,即该括号字符串合法,反之则是非法的。观察这个匹配规律,不难发现与栈“先入后出”的特点相符合,因此我们可以直接创建一个栈进行实现。

具体代码如下:

typedef char STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量
}ST;

//判空
bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}
//初始化
void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
//销毁
void STDestroy(ST* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
//入栈
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->capacity == ps->top)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* p = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
		ps->a = p;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
//出栈
void STPop(ST* ps)
{
	assert(ps);
	assert(ps->a);
	assert(!STEmpty(ps));
	ps->top--;
}
//取栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->a);
	assert(!STEmpty(ps));
	return ps->a[ps->top - 1];
}

bool isValid(char * s)
{
    ST ps;
    STInit(&ps);
    int i=0;
    for(i=0;i<strlen(s);i++)
    {
        if(s[i]=='('||s[i]=='{'||s[i]=='[')//左括号入栈
        {
            STPush(&ps,s[i]);
        }
        else//右括号与栈顶元素进行匹配
        {
            if(STEmpty(&ps))//栈中为空,说明括号数量不匹配
            {
                return false;
            }
            else if((STTop(&ps)=='('&&s[i]!=')')||
                    (STTop(&ps)=='['&&s[i]!=']')||
                    (STTop(&ps)=='{'&&s[i]!='}'))//栈中不为空,但括号样式不匹配
            {
                return false;
            }
            else//匹配成功,栈顶元素出栈
            {
                STPop(&ps);
            }
        }
    }
    if(STEmpty(&ps))//全部遍历完之后,栈中为空,说明全部匹配成功
    {
        return true;
    }
    else//栈中不为空,说明数量不匹配
    {
        return false;
    }
	STDestroy(&ps);
}

 运行结果:

用栈实现队列:

题目描述:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。

 首先要知道栈的特点是“先入后出”,因为此特点,把栈1中的数据移动到栈2中时,数据的顺序会倒过来,如下:

数据入栈顺序是1、2、3、4,此时再从栈2中执行出栈操作,数据出栈顺序也是1、2、3、4,可以满足队列“先入先出”的功能,因此我们不妨把一个栈专门同来进数据(push),另一个栈专门用来出数据(pop)。 

 每次进数据都压入push栈,出数据都从pop栈出,若pop栈为空,则把push栈的数据都压入pop栈后再出数据。

 代码如下:

typedef int STDataType;
typedef struct Stack
{
    STDataType* a;
    int top;//栈顶
    int capacity;//容量
}ST;
typedef struct
{
    ST push;
    ST pop;
} MyQueue;

//初始化
void STInit(ST* ps)
{
    assert(ps);
    ps->a = NULL;
    ps->capacity = 0;
    ps->top = 0;
}
//判空
bool STEmpty(ST* ps)
{
    assert(ps);
    return ps->top == 0;
}
//销毁
void STDestroy(ST* ps)
{
    free(ps->a);
    ps->a = NULL;
    ps->capacity = 0;
    ps->top = 0;
}
//入栈
void STPush(ST* ps, STDataType x)
{
    assert(ps);
    if (ps->capacity == ps->top)
    {
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        STDataType* p = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
        ps->a = p;
        ps->capacity = newcapacity;
    }
    ps->a[ps->top] = x;
    ps->top++;
}

//出栈
void STPop(ST* ps)
{
    assert(ps);
    assert(ps->a);
    assert(!STEmpty(ps));
    ps->top--;
}
//取栈顶元素
STDataType STTop(ST* ps)
{
    assert(ps);
    assert(ps->a);
    assert(!STEmpty(ps));
    return ps->a[ps->top - 1];
}
//创建我的队列
MyQueue* myQueueCreate()
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->push);
    STInit(&obj->pop);
    return obj;
}
//入队
void myQueuePush(MyQueue* obj, int x)
{
    STPush(&obj->push, x);
}
//出队
int myQueuePop(MyQueue* obj)
{
    if (STEmpty(&obj->pop))
    {
        while (!STEmpty(&obj->push))
        {
            STDataType x = STTop(&obj->push);
            STPop(&obj->push);
            STPush(&obj->pop, x);
        }
    }
    STDataType front = STTop(&obj->pop);
    STPop(&obj->pop);
    return front;
}
//取队头
int myQueuePeek(MyQueue* obj)
{
    if (STEmpty(&obj->pop))
    {
        while (!STEmpty(&obj->push))
        {
            STDataType x = STTop(&obj->push);
            STPop(&obj->push);
            STPush(&obj->pop, x);
        }
    }
    STDataType front = STTop(&obj->pop);
    return front;
}
//我的队列判空
bool myQueueEmpty(MyQueue* obj)
{
    return (STEmpty(&obj->push) && STEmpty(&obj->pop));
}
//销毁我的队列
void myQueueFree(MyQueue* obj)
{
    STDestroy(&obj->push);
    STDestroy(&obj->pop);
    free(obj);
}

运行结果:

用队列实现栈:

题目描述:

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

  • 你只能使用队列的基本操作 —— 也就是 push to backpeek/pop from frontsize 和 is empty 这些操作。

首先要知道队列的特点是“先进先出”,因为此特点,将队列1中的数据移动到队列2中时,数据的顺序不会变,如下:

 数据的从队列1进队顺序是1、2、3、4,如直接从队列2出队,则出队顺序也是1、2、3、4,无法满足栈的“先进后出”的特点。因此,想要通过队列实现栈,要始终保证至少一个队列为空(若两个队列都为空,则只能执行判空和压入数据的操作),这样在出数据时,把不为空队列(假设有n个数据)的前n-1个数据移动到空队列中,再出最后一个数据,这样不断在两个队列之间导数据,就能实现把后入的数据先出出去,而想要压入数据时,直接在非空的队列队尾直接插入即可,这样就能实现栈“先进后出”的特点。

 代码如下:

typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Que;
typedef struct
{
	Que p1;
	Que p2;
} MyStack;
//判空 :空返回1,非空返回0
bool QueueEmpty(Que* pq)
{
	assert(pq);
	return pq->head == NULL;
}
//初始化
void QueueInit(Que* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;
}
//销毁
void QueueDestroy(Que* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* p = cur->next;
		free(cur);
		cur = p;
	}
	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;
}
//入队
void QueuePush(Que* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->head == NULL)
	{
		pq->head = newnode;
		pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}
//出队
void QueuePop(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));//要有数据
	if (pq->head->next == NULL)//只有一个节点
	{
		free(pq->head);
		pq->head = NULL;
		pq->tail = NULL;
	}
	else
	{
		QNode* cur = pq->head->next;
		free(pq->head);
		pq->head = cur;
	}
	pq->size--;
}
//取队头
QDataType QueueFront(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}
//取队尾
QDataType QueueBack(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}
//有效数据
int QueueSize(Que* pq)
{
	assert(pq);
	return pq->size;
}
//创建我的栈
MyStack* myStackCreate()
{
	MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
	QueueInit(&obj->p1);
	QueueInit(&obj->p2);
	return obj;
}
//入栈
void myStackPush(MyStack* obj, int x)
{
	if (!QueueEmpty(&obj->p1))
	{
		QueuePush(&obj->p1, x);
	}
	else
	{
		QueuePush(&obj->p2, x);
	}
}
//出栈
int myStackPop(MyStack* obj)
{
	QDataType top = 0;
	if (!QueueEmpty(&obj->p1))
	{
		while (QueueSize(&obj->p1) > 1)
		{
			QDataType a = QueueFront(&obj->p1);
			QueuePop(&obj->p1);
			QueuePush(&obj->p2, a);
		}
		top = QueueFront(&obj->p1);
		QueuePop(&obj->p1);
	}
	else
	{
		while (QueueSize(&obj->p2) > 1)
		{
			QDataType a = QueueFront(&obj->p2);
			QueuePop(&obj->p2);
			QueuePush(&obj->p1, a);
		}
		top = QueueFront(&obj->p2);
		QueuePop(&obj->p2);
	}
	return top;
}
//取栈顶
int myStackTop(MyStack* obj)
{
	if (!QueueEmpty(&obj->p1))
	{
		return QueueBack(&obj->p1);
	}
	else
	{
		return QueueBack(&obj->p2);
	}
}
//判空
bool myStackEmpty(MyStack* obj)
{
	return (QueueEmpty(&obj->p1) && QueueEmpty(&obj->p2));
}
//销毁我的栈
void myStackFree(MyStack* obj)
{
	QueueDestroy(&obj->p1);
	QueueDestroy(&obj->p2);
	free(obj);
}

运行结果:

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

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

相关文章

R语言之 dplyr 包

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/dive-into-AI 】或者公众号【AIShareLab】回复 R语言 也可获取。 文章目录 1.使用 filter( ) 和 slice( ) 筛选行2.使用 arrange( ) 排列行3. 使用 select( ) 选择列4.使用 mutate( ) 添加新变量5.使…

FMCW雷达基于时分复用波形(TDMA) 3D点云获取方法的仿真

摘要&#xff1a;通过设置时分复用(TDMA)波形结合FMCW毫米波雷达仿真获取目标的距离、速度和方位角3D点云信息。在本案例中&#xff0c;首先通过发射天线交替发射FMCW波形并通过接收天线依次接收回波信号从而得到雷达原始数据&#xff0c;其次对获取的原始数据依次经行距离、速…

电脑怎么把视频转换gif动图?视频生成gif的操作步骤

如果你也想把一些精彩的视频转gif图片&#xff08;https://www.gif.cn&#xff09;的话&#xff0c;今天的文章你可千万不要错过&#xff0c;利用专业的视频转gif工具&#xff0c;轻松在线视频转gif&#xff0c;操作简单又方便&#xff0c;支持电脑、手机双端操作&#xff0c;赶…

金蝶云星空和管易云接口打通对接实战

金蝶云星空和管易云接口打通对接实战 对接系统金蝶云星空 金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上&#xff0c;提供了标准的管理模式&#xff1b;通过标准的业务架构&#xff1a;多会计准则、多币别、多地点、多组织、多税制应用框架等&#xff0c;有效支持企业的运…

静电中和风机在所具有的的优点

半导体生产过程中&#xff0c;静电积聚和离子污染是常见的问题&#xff0c;会对产品质量和工艺稳定性造成负面影响。为了解决这个问题&#xff0c;可以采用专门用于半导体自动化的静电消除/中和离子风机。 静电消除/中和离子风机是一种集静电消除和离子中和功能于一体的装置。…

Arnold置乱

一、Arnold置乱概述 Arnold变换是俄国数学家弗拉基米尔阿诺德&#xff08;Vladimir Igorevich Arnold&#xff09;提出&#xff0c;Arnold将其应用在遍历理论研究中。由于Arnold本人最初对一张猫的图片进行了此种变换&#xff0c;因此它又被称为猫脸变换&#xff08;cat映射&am…

24 | 紧跟时代步伐:微服务模式下API测试要怎么做?

微服务架构&#xff08;Microservice Architecture&#xff09; 微服务是一种架构风格。在微服务架构下&#xff0c;一个大型复杂软件系统不再由一个单体组成&#xff0c;而是由一系列相互独立的微服务组成。其中&#xff0c;各个微服务运行在自己的进程中&#xff0c;开发和部…

【pdf密码】PDF文件,无密码取消限制

PDF文件设置了限制编辑&#xff0c;会导致什么情况呢&#xff1f;比较常见的就是无法编辑、无法复制粘贴、无法打印或者打印文件清晰度差。这些都是PDF限制编辑导致的&#xff0c;想要编辑文件&#xff0c;我们就需要取消限制编辑&#xff0c;但是有些时候&#xff0c;大家可能…

静电中和设备在半导体自动化生产中起到了怎样的作用

静电中和设备在半导体自动化生产中起到了重要的作用。在半导体生产过程中&#xff0c;由于材料的摩擦、粉尘的飞扬、人员的移动等原因&#xff0c;会产生大量的静电电荷。这些静电电荷如果不得到有效的中和处理&#xff0c;会对生产过程和产品质量产生严重的影响。 静电中和设…

LPC1768运行threadx数组越界导致出现硬件错误死机问题的排查

移植了threadx后运行发现程序莫名跑飞&#xff0c;停留在 HardFaultHandler 即硬件错误异常 调试过程中发现在汇编启动文件启动后跳转main函数即刻就发生了错误异常&#xff0c;先排除是在操作系统运行过程中的问题&#xff0c;而且是硬件错误异常所以先对导致改错误的可能进行…

ENSP操作平台命令汇总一(第五课)

一 Ensp基础指令操作 1 ipconfig 查看 pc机的IP地址2 ping 连接的IP地址 3 system-view 进入系统视图4 [Huawei]interface GigabitEthernet 0/0/1 进入接口视图 过0/0/15 quit 返回上一层视图6 ctrlZ 快速返回用户视图7 [sy]sysname tedu-ntd-lswl 进入系统视…

Java --- 内部类

目录 一、什么是内部类 二、为什么需要内部类 三、内部类的分类 3.1、成员内部类 3.2、局部内部类 四、练习 一、什么是内部类 将一个类A定义在另一个类B里面&#xff0c;里面的那个类A就称为内部类&#xff08;InnerClass&#xff09;&#xff0c;类B则称为外部类&#…

SQL 错误 [22007]: ERROR: invalid input syntax for type date: ““

0. 背景 PG数据库一张表有这样一个varchar类型的字段end_date,存储的值是格式化后的年月日日期如 2024-08-10 现在我需要根据当前日期与end_date的差值作为where条件过滤,我的写法 select …… from my_table_name where current_date - cast (end_date as date) >100报错…

苹果“迎难而上”,印度赚印度花,扩大产能,推动手机制造业发展

根据报道&#xff0c;苹果公司在由印度当地媒体 Business Today 报道的会议中表示&#xff0c;他们计划扩大在印度的生产产能。这也进一步显示了苹果对印度市场的重视程度。 据统计数据显示&#xff0c;印度已成为苹果第五大iPhone市场&#xff0c;其市场营收超越了法国和德国&…

React绑定antd输入框,点击清空或者确定按钮实现清空输入框内容

其实实现原理和vue的双向绑定是一样的&#xff0c;就是监听输入框的onChange事件&#xff0c;绑定value值&#xff0c;当输入框内容发生变化后&#xff0c;就重新设置这个value值。 示例代码&#xff1a;我这里是统一在handleCancel这个函数里面处理清空逻辑了&#xff0c;你们…

再写CentOS7升级OpenSSL-1.0.1U

本文在CentOS7.4以及TencentOS 2.4上测试通过。 原系统自带OpenSSL 1.0.2k-fips。 编译安装方法跟之前的没啥区别。 从官网下载1.0.1u版https://www.openssl.org/source/ 使用tar解包 tar xfz openssl-1.0.1u.tar.gz 依次执行如下&#xff1a; cd openssl-1.0.1u ./con…

pdf转ppt软件哪个好用?推荐一个好用的pdf转ppt软件

在日常工作和学习中&#xff0c;我们经常会遇到需要将PDF文件转换为PPT格式的情况。PDF格式的文件通常用于展示和保留文档的原始格式&#xff0c;而PPT格式则更适合用于演示和展示。为了满足这一需求&#xff0c;许多软件提供了PDF转PPT的功能&#xff0c;使我们能够方便地将PD…

成都优优聚做美团代运营还有市场吗?

成都优优聚公司是一家专注于美团代运营的企业。作为美团的第三方代运营商&#xff0c;公司致力于帮助商家提升线上形象&#xff0c;提高销售额&#xff0c;实现转型升级。在与美团合作的多年间&#xff0c;公司已积累了丰富的经验和优秀的专业团队。 作为一个代运营商&#xff…

VK0192是标准LCD显示面板/液晶显示屏驱动芯片(IC)-24SEG×8COM

产品品牌&#xff1a;永嘉微电/VINKA 产品型号&#xff1a;VK0192 封装形式&#xff1a;LQFP44 概述 VK0192是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大192点&#xff08;24SEGx8COM&#xff09; 的LCD屏。单片机可通过3/4线串行接口配置显示参数和发送显示数据…

恢复照片软件,记好这几个,照片恢复很简单!

“我真的很喜欢拍摄各种各样的照片&#xff0c;然后在电脑上进行修图。但是吧&#xff01;我比较马虎&#xff0c;在挑选照片时经常会误删一些很好看的照片。真的很需要一款专门恢复照片的软件&#xff0c;想问问有什么好的推荐吗&#xff1f;” 无意中删除了重要的照片真的会让…