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

【刷题之路】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. 用队列实现栈是一样的,也是逻辑复杂,结构稍复杂一点儿。但也是值得我们多练习几遍,以加深对栈和队列的理解。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网站测试的主要方法

网站测试的主要方法 网站测试是保证网站质量的重要手段&#xff0c;通过对网站进行测试可以及时发现问题并修复&#xff0c;提高用户体验和网站的可靠性。本文将介绍网站测试的主要方法。 1.功能测试&#xff1a;测试网站的所有功能是否正常。通过模拟用户的操作&#xff0c;确…

在外包干了三年,我废了……不吹不黑!

没错&#xff0c;我也干过外包&#xff0c;一干就是三年&#xff0c;三年后&#xff0c;我废了…… 虽说废的不是很彻底&#xff0c;但那三年我几乎是出差了三年、玩了三年、荒废了三年&#xff0c;那三年&#xff0c;我的技术能力几乎是零成长的。 说起这段三年的外包经历&a…

文档管理-gitlab+markdown网页插件

特点 使用git进行版本管理&#xff0c;本地编辑使用Typora。使用gitlab进行权限管理可以在线阅读通过Markdown在线阅读插件实现&#xff0c;可显示目录显示与链接跳转&#xff0c;界面优于自带的wiki。 与其他方式对比 gitlab的wiki&#xff1a;显示界面效果不好&#xff0c…

【数据结构】栈及其实现

目录 &#x1f920;前言 什么是栈&#xff1f; 栈的定义及初始化 栈的定义 栈的初始化 栈的判空 栈顶压栈 栈顶出栈 栈的数据个数 栈的销毁 完整代码 总结 &#x1f920;前言 学了相当长一段时间的链表&#xff0c;总算是跨过了一个阶段。从今天开始我们将进入栈和…

[IOT物联网]Python快速上手开发物联网上位机程序——前言

一、什么是Python Python是一种简单易学、高级、通用的编程语言。它是一种解释型语言&#xff0c;不需要编译即可运行&#xff0c;因此可以快速地进行开发和测试。Python具有简洁优美的语法&#xff0c;使用它可以提高生产力和代码可读性。Python拥有强大的标准库和第三方库&am…

Linux Shell 实现一键部署virtualbox

VirtualBox 前言 VirtualBox 是一款开源虚拟机软件。VirtualBox 是由德国 Innotek 公司开发&#xff0c;由Sun Microsystems公司出品的软件&#xff0c;使用Qt编写&#xff0c;在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。Innotek 以 GNU General Public Licens…

孙鑫VC++第四章 1.简单绘图-MFC消息映射机制

1. MFC消息映射机制 接下来将剖析MFC消息映射机制&#xff0c;探讨发送给窗口的消息是如何被MFC框架通过窗口句柄映射表和消息映射表来用窗口类的处理函数进行响应的。另外&#xff0c;还将讲述“类向导”这一工具的运用&#xff0c;讨论设备描述表及其封装类CDC的使用&#x…

玩转ChatGPT:魔改文章成果格式

一、写在前面 首先&#xff0c;我让小Chat替我吐槽一下&#xff1a; 科研人员天天都在填各种表格&#xff0c;简直成了我们的“表格王子”和“表格公主”。从申请项目、提交论文到汇报成果&#xff0c;表格无处不在。我们填表格的时候总是期待着它能让我们的工作更高效、更顺…

遇到一个同事,喜欢查其他同事的BUG,然后截图发工作大群里,还喜欢甩锅,该怎么办?...

职场上都有哪些奇葩同事&#xff1f; 一位网友吐槽&#xff1a; 遇到一个同事&#xff0c;喜欢查同级别同事的bug&#xff0c;截图发工作群&#xff0c;甚至发大群里&#xff0c;还喜欢甩锅&#xff0c;该怎么办&#xff1f; 职场工贼&#xff0c;人人喊打&#xff0c;网友们纷…

asm 加盘 udev 重启 导致网络异常

Network interface going down when dynamically adding disks to storage using udev in RHEL 6 (Doc ID 1569028.1)正在上传…重新上传取消To Bottom In this Document APPLIES TO: Oracle Database - Enterprise Edition - Version 11.2.0.3 and later Oracle Net Servi…

UART驱动情景分析-read

一、源码框架回顾 shell读数据&#xff0c;一开始的时候没有就休眠。数据从串口发送到驱动&#xff0c;驱动接收到中断&#xff0c;驱动读取串口数据&#xff0c;这个数据会传给行规程。 行规程获取到数据后&#xff0c;会回显。按下删除就删除一个字符&#xff0c;按下回车&am…

【Linux升级之路】3_Linux进程概念

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux升级之路】 ✒️✒️本篇内容&#xff1a;认识冯诺依曼系统&#xff0c;操作系统概念与定位&#xff0c;深入理解进程概念&#xff08;了解PCB&…

【#ifndef, #define, 和 #endif】

前言 学习AFNetWoring源码的时候&#xff0c;在AFN的h借接口文件又看到了这几个宏定义&#xff0c;学习记录一下。 作用 #ifndef, #define, 和 #endif是C/CPP的预处理指令&#xff0c;常常用来条件编译和防止头文件重复包含。 简介 #ifndef 它是if not define的简写&…

Cy5.5-PEG-SH近红外荧光PEG试剂 Cyanine5.5-PEG-SH,Thiol-PEG-Cy5.5可用于活体成像

Cy5.5-PEG-SH &#xff0c;Cy5.5聚乙二醇巯基 英文名称&#xff1a;Cy5.5-PEG-SH 中文名称&#xff1a;Cy5.5聚乙二醇巯基 性状: 深蓝色固体或粘性液体&#xff0c;取决于分子量 溶剂&#xff1a;溶于水、 DMSO等常规性有机溶剂 激发/发射波长&#xff1a;684 nm/710 nm …

学习HCIP的day.06

十一、OSFP扩展知识点 1、关于OSPF状态机的问题 &#xff08;1&#xff09;在MA网络中&#xff08;要进行DR/BDR选举&#xff09;存在7种状态机&#xff0c;init是路由器A收到邻居B的hello包&#xff0c;但该hello包中没有A的RID&#xff1b; &#xff08;2&#xff09;在点到…

js跨域的解决方案

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

手把手教你用代码画架构图 | 京东云技术团队

作者&#xff1a;京东物流 覃玉杰 1. 前言 本文将给大家介绍一种简洁明了软件架构可视化模型——C4模型&#xff0c;并手把手教大家如何使用代码绘制出精美的C4架构图。 阅读本文之后&#xff0c;读者画的架构图将会是这样的&#xff1a; 注&#xff1a;该图例仅作绘图示例使…

【PCIE体系结构十一】部分物理层发送接收逻辑细节

&#x1f449;个人主页&#xff1a;highman110 &#x1f449;作者简介&#xff1a;一名硬件工程师&#xff0c;持续学习&#xff0c;不断记录&#xff0c;保持思考&#xff0c;输出干货内容 参考书籍&#xff1a;《PCI.EXPRESS系统体系结构标准教材 Mindshare》 目录 物理层…

【复杂网络建模】——通过图神经网络来建模分析复杂网络

目录 一、复杂网络介绍 二、复杂网络建模分析方法 三、基于图神经网络来建模 1、数据准备 2、构建图神经网络模型 3、学习节点和边的表示 4、特征提取和预测 5、模型评估和优化 四、可视化建模分析 1、初始网络可视化 2、特征可视化 一、复杂网络介绍 复杂网络是指…

软件测试专业应届生应如何提高职场竞争力

一&#xff1a;巩固专业知识 背景&#xff1a;笔者已经做了几年的打工人&#xff0c;以个人经验给软件测试专业应届生一些建议。 推荐需要掌握的知识&#xff1a; 1、软件测试基础知识&#xff08;软件生命周期每个阶段工作需了解&#xff09; 2、熟悉SQL/MySQL/Oracle数据库&…