【刷题之路】LeetCode 232. 用栈实现队列

news2024/11/27 15:44:39

【刷题之路】LeetCode 232. 用栈实现队列

  • 一、题目描述
  • 二、解题
    • 1、图解主要思路
    • 2、先实现栈
    • 3、实现各个接口
      • 3.1、初始化接口
      • 3.2、入队接口
      • 3.3、出队接口
      • 3.4、取队头接口
      • 3.5、判空接口
      • 3.6、释放接口

一、题目描述

原题连接: 232. 用栈实现队列
题目描述:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:

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

说明:

  1. 你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  2. 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

输入:
[“MyQueue”, “push”, “push”, “peek”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  1. 1 <= x <= 9
  2. 最多调用 100 次 push、pop、peek 和 empty
  3. 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

进阶:
你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

二、解题

1、图解主要思路

其实这题和[225. 用队列实现栈]一样,也是属于栈和队列的应用练习题。
所以其实现思路也是相似的,也是通过返回出队元素的方法来模拟出队列的先进先出结构。
其实这一题也是要用到两个栈,但是我们怎样设计思路呢?
其实我们可以对这两个栈的任务进行分工,一个栈专门用来入队,一个栈专门用来出栈:
在这里插入图片描述
那么对于入队操作,我们就可以直接将数据压入到“入队栈”中:
在这里插入图片描述
而对于出队操作,我们就要先检查“出队栈”是否为空,如果为空的话,就要先将“入队栈”中的数据逐一弹出再压入“出队栈”中:
在这里插入图片描述
这其实就等于将“入队栈”中的数据给逆置了,然后我们就可以将“出队栈”的栈顶数据弹栈,最后返回了。
而在后面的出队操作中,如果“出队栈”不为空,我们就可以直接将“出队栈”的栈顶数据弹出并返回了,直到“出队栈”再次为空,那我们就要再次将“入队栈”清空。
不知道大家有没有注意到,其实我们可以把这两个栈形象的看成一个一根U型管的两端:
在这里插入图片描述
我们可以假设“入队栈”的数据是通过下边的弯的管道“流”过去的,这样即完成了“入队栈”的数据的逆序,并且也符合了先进先出。

好了,其实这一道题的主要实现逻辑就是这一点,剩下来的就是结构的问题了。

2、先实现栈

同样的,因为我这里选择的是C语言实现,所以我们要先把栈实现一下,我这里就直接赋值我之前的【数据结构】简单到有摸鱼负罪感的栈的实现中的栈的实现了:

// 重定义数据类型
typedef int DataType;

// 定义栈结构
typedef struct stack {
	DataType* data;
	int top;
	int capacity;
} Stack;

// 栈的初始化
void StackInit(Stack* ps);

// 压栈
void StackPush(Stack* ps, DataType x);
// 弹栈
void StackPop(Stack* ps);
// 返回栈顶数据
DataType StackTop(Stack* ps);
// 返回栈的数据个数
int StackSize(Stack* ps);
// 判断栈是否为空
bool StackEmpty(Stack* ps);
// 栈的销毁
void DestroyStack(Stack* ps);

// 栈的初始化
void StackInit(Stack* ps) {
	assert(ps);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

// 压栈
void StackPush(Stack* ps, DataType x) {
	assert(ps);
	// 检查是否需要增容
	if (ps->top == ps->capacity) {
		int newCapacity = ps->capacity == 0 ? 10 : ps->capacity * 2;
		DataType* temp = (DataType*)realloc(ps->data, newCapacity * sizeof(DataType));
		if (NULL == temp) {
			perror("ralloc fail!\n");
			exit(-1);
		}
		ps->data = temp;
		ps->capacity = newCapacity;
	}
	ps->data[ps->top] = x;
	ps->top++;
}

// 弹栈
void StackPop(Stack* ps) {
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}

// 返回栈顶数据
DataType StackTop(Stack* ps) {
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->data[ps->top - 1];
}

// 返回栈的数据个数
int StackSize(Stack* ps) {
	assert(ps);
	assert(ps->top >= 0);
	return ps->top;
}

// 判断栈是否为空
bool StackEmpty(Stack* ps) {
	assert(ps);
	return ps->top == 0;
}

// 栈的销毁
void DestroyStack(Stack* ps) {
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

3、实现各个接口

3.1、初始化接口

在myQueueCreate接口中,我们不仅要将队列开辟好,同时也要将队列中的,栈给初始化了,初始化就直接调用栈中实现的接口即可。

typedef struct {
    Stack headStack; // 队头栈,用于出队
    Stack tailStack; // 队尾栈,用于入队
} MyQueue;

MyQueue* myQueueCreate() {
    MyQueue *queue = (MyQueue*)malloc(sizeof(MyQueue));
    if (NULL == queue) {
        perror("malloc fail!\n");
        exit(-1);
    }
    StackInit(&queue->headStack);
    StackInit(&queue->tailStack);
    return queue;
}

3.2、入队接口

入队没什么好说的,统一将数据压入到“入队栈”中:

void myQueuePush(MyQueue* obj, int x) {
    // 对于入队,我们可以统一把数据压入队尾栈
    StackPush(&obj->tailStack, x);
}

3.3、出队接口

出队就要分两种情况,如果“出队栈”不为空,就直接将“出队栈”的栈顶元素弹出即可,如果为空,这要将“入队栈”清空,将数据压入到“出队栈”中。

int myQueuePop(MyQueue* obj) {
    int returnVal = 0;
    if (!StackEmpty(&obj->headStack)) {
        returnVal = StackTop(&obj->headStack);
        StackPop(&obj->headStack);
    } else {
        // 先将队尾栈的数据全部弹出,压到队尾栈
        while (!StackEmpty(&obj->tailStack)) {
            int temp = StackTop(&obj->tailStack);
            StackPop(&obj->tailStack);
            StackPush(&obj->headStack, temp);
        }
        returnVal = StackTop(&obj->headStack);
        StackPop(&obj->headStack);
    }
    return returnVal;
}

要注意的是,在真正弹栈之前需要先将栈顶元素的值保存,最后返回。

3.4、取队头接口

取队头其实和出队是一样的逻辑,只不过不用将数据真正弹栈:

int myQueuePeek(MyQueue* obj) {
    // 这个操作其实也和Pop一样,如果队头栈为空,就要先队尾栈的数据全都压入到队头栈,返回栈顶
    if (StackEmpty(&obj->headStack)) {
        // 先将队尾栈的数据全部弹出,压到队尾栈
        while (!StackEmpty(&obj->tailStack)) {
            int temp = StackTop(&obj->tailStack);
            StackPop(&obj->tailStack);
            StackPush(&obj->headStack, temp);
        }
    }
    return StackTop(&obj->headStack);
}

3.5、判空接口

判空的话,我们返回两个栈是否同时为空的判断结果即可:

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->headStack) && StackEmpty(&obj->tailStack);
}

3.6、释放接口

如果队列不为空的话,还要将队列里的两个栈先释放掉,如果为空,我们就直接释放掉队列即可。

void myQueueFree(MyQueue* obj) {
    if (!myQueueEmpty(obj)) {
        // 如果队列不为空,我们就要先将栈销毁
        DestroyStack(&obj->headStack);
        DestroyStack(&obj->tailStack);
    }
    free(obj);
}

总结起来,这一题其实和225. 用队列实现栈是一样的,也是逻辑复杂,结构稍复杂一点儿。但也是值得我们多练习几遍,以加深对栈和队列的理解。

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

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

相关文章

Babylon.js大规模场景优化实践

在本文中&#xff0c;我们将重点介绍用于优化 Babylon.js 海港场景的优化和架构技术。 我们的场景总共有超过 600 个网格和 1,000,000 个顶点。 在我们的 2018 Macbook Pro 上&#xff0c;它在 Google Chrome 中始终以 45 FPS 的速度运行。 我们发现 Firefox 约为 40 FPS&#…

公厕卫生间除臭杀菌空气净化解决方案

人每天平均大约有80%以上时间是在室内度过&#xff0c;室内空气同时面临着化学污染、物理污染和生物污染&#xff0c;据统计室内污染比室外高5~10倍&#xff0c;因此室内空气质量问题对人的伤害比室外污染更大。常见的空气污染有病毒、烟雾、甲醛、细菌、PM2.5等&#xff0c;如…

淘宝商品详情数据采集,支持高并发请求

一、如何通过手动方式查看阿里巴巴商品详情页面的数据 1.淘宝天猫商品详情 API 接口&#xff08;item_get - 获得淘宝商品详情接口&#xff09;&#xff0c;淘宝API 接口代码对接可以获取到宝贝 ID&#xff0c;宝贝标题&#xff0c;价格&#xff0c;优惠价&#xff0c;掌…

C++优化方法

C优化方法 文章目录 C优化方法1.整数运算效率高于浮点2.除法和取余4.通过2的幂次进行除法和取余数5.使用数组下标6.全局变量->局部变量7.指针值不改变的->拷贝到局部变量8.变量类型9.局部变量10.指针11.指针链12.条件执行13.布尔表达式和范围检查14.布尔表达式和零值比较…

【UE4 像素流 WEBUI插件】部署像素流

目录 一、单实例本地像素流送 步骤 1. 勾选插件 2. 打包工程并启动信令服务器 3. 创建快捷方式并启动游戏 二、单实例局域网像素流送 步骤 1. 编辑cirrus.js 2. 编辑快捷方式属性 3. 启动 三、集成WEBUI插件 一、单实例本地像素流送 步骤 1. 勾选插件 勾选使用“Pix…

数字化时代下,企业如何利用数字化提升企业竞争力?

在数字化时代的今天&#xff0c;企业越来越意识到数字化的重要性。数字化已经成为企业竞争的关键。在数字化时代下&#xff0c;企业的竞争力也已经从传统的硬实力向软实力转变。企业需要利用数字化技术来提高竞争优势&#xff0c;从而在激烈的竞争中脱颖而出。 目前&#xff0c…

Mysql_行锁、临键锁、间隙锁的理解

目录 行锁间隙锁临键锁总结 行锁 行锁&#xff0c;也称为记录锁。 当我们针对主键或者唯一索引加锁的时候&#xff0c;Mysql默认会对查询的这一行数据加行锁&#xff0c;避免其他事务对这一行数据进行修改。 间隙锁 间隙锁&#xff0c;顾名思义&#xff0c;就是锁定一个索引…

浅谈作为程序员如何写好文档:结构化写作

我作为从一名懵懂的实习生转变为工程师的工作经历中&#xff0c;伴随着技术经验的成长&#xff0c;也逐渐意识到了编写文档是知识和经验传递给其他人的最有效方式。通过文档&#xff0c;可以分享我的技术知识和最佳实践&#xff0c;使其他人更好地理解我的工作。在这里&#xf…

图解 SQL 执行顺序,清晰明了

这是一条标准的查询语句: 这是我们实际上SQL执行顺序&#xff1a; 我们先执行from,join来确定表之间的连接关系&#xff0c;得到初步的数据 where对数据进行普通的初步的筛选 group by 分组 各组分别执行having中的普通筛选或者聚合函数筛选。 然后把再根据我们要的数据进行…

alias设置快捷键vim使用说明(解决服务器上输入长指令太麻烦的问题)

1. vi ~/.bashrc打开 2. (watch -n 1 gpustat 查看gpu使用情况 太麻烦)输入i进行编辑&#xff0c;最后一行输入 alias watchgpuwatch -n 1 gpustat alias gpuwatch -n 1 gpustat alias torch180source activate torch180 3. 按esc&#xff0c;然后输入:wq保存退出 4. source…

多轴加工-可变轴轮廓铣_刀轴控制策略

可变轴轮廓铣_刀轴 刀轴是可变轴轮廓铣最重要的核心参数之一&#xff0c;控制好刀轴对生成的刀路质量至关重要。UG NX可变轴轮廓铣提供了非常丰富的刀轴控制方法&#xff0c;常用的包括远离/朝向直线&#xff08;点&#xff09;、相对于/垂直于驱动体、侧刃驱动体、插补等&…

在Apex中获取Site URL

Foreword 目前SF暂未提供直接有效的方法在Apex获取SiteURL&#xff0c;我们可以在Idea (Access URL for a Site or Community from Apex)页面投票&#xff0c;除了下面提供的一种hack思路&#xff0c;当然也可以通过Custom Label手动维护。 Format of Site URL Sandbox site …

如何搭建自己的写作素材库,快来学,方法高效简单

我们平时看过的书&#xff0c;做过的事&#xff0c;不及时记下来&#xff0c;很可能过几天就忘记了。由此看来&#xff0c;搭建自己的写作素材库非常有必要。尤其是写作者&#xff0c;写稿的速度取决于自己写作素材的储备量&#xff0c;你储备的素材越多&#xff0c;写作时便可…

【算法学习系列】01 - 求某个数组中的任意两个位置之间的累加和

文章目录 背景解决思路代码实现 背景 已经呆在自己的舒适圈有很长一段时间了&#xff08;公司快3年了&#xff0c;业务都熟的差不多了&#xff09;&#xff0c;决定开始改变&#xff08;任何时候都不晚&#xff09;&#xff0c;尝试学习解决一些算法题&#xff0c;给自己一些适…

自媒体可以去哪里找免费图片素材?

推荐6个超好用的图片素材网站&#xff0c;免费下载&#xff0c;还可以商用&#xff0c;建议收藏起来~ 1、菜鸟图库 https://www.sucai999.com/pic.html?vNTYwNDUx 菜鸟图库是一个综合性素材网站&#xff0c;站内有大量的设计、自媒体等相关素材&#xff0c;像图片素材就非常…

Linux篇2

Linux 0. 终端提示信息1. 文件目录结构1.1 文件目录 2. 文本编辑器VI/VIM2.1 VIM编辑器2.1 一般模式2.2 编辑模式2.3 命令模式 3. 网络配置3.1 VMware提供的三种网络连接模式3.2 静态配置网络IP地址3.3 配置主机名3.3.1 修改主机名3.3.2 配置主机名-IP地址映射关系&#xff1a;…

离散化详解

一.概念 把无限空间中有限的个体映射到有限的空间中去&#xff0c;以此提高算法的时空效率。通俗的说&#xff0c;离散在不改变数据相对大小的条件下&#xff0c;对数据进行相应的缩小。 二.适用范围 数组中元素值域很大&#xff0c;但个数不是很多。 比如将a[][1,3,100,2000,…

CloudCompare二次开发之如何通过PCL进行点云滤波?

文章目录 0.引言1.CloudCompare界面设计滤波(filter)按钮2.PassThrough直通滤波器3.VoxelGrid体素滤波器4.UniformSampling均匀采样5.StatisticalOutlierRemoval统计滤波器6.RadiusOutlierRemoval半径滤波器7.ConditionRemoval条件滤波器8.ProjectInliers投影滤波器9.ModelOutl…

js跨域的解决方案

一、什么是跨域&#xff1f; 指的是浏览器不能执行其他网站的脚本&#xff0c;简单来说是浏览器同源政策的限制&#xff0c;浏览器针对于ajax的限制。 同源政策 两个页面拥有相同的 协议&#xff0c;端口&#xff0c;域名 就是同源&#xff0c;如果有一个不相同就是不同源…

【SQL】作为前端,应该了解的SQL知识(第四弹)

&#x1f4d1;集合运算 集合运算就是对满足同一规则的记录进行的加减等四则运算。 &#x1f449; 对行数进行增减。 &#x1f4c3;UNION 取并集 集合运算符会去除重复的记录 SELECT product_id, product_nameFROM Product **UNION** SELECT product_id, product_nameFROM …