当前位置:网站首页>LeetCode每日一练 —— 225. 用队列实现栈
LeetCode每日一练 —— 225. 用队列实现栈
2022-08-02 10:31:00 【飞向星的客机】
前言
Wassup guys!我是Edison
今天是 LeetCode 上的 leetcode 225. 用队列实现栈
Let’s get it!
1. 题目描述
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(
push
、top
、pop
和empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回 true ;否则,返回 false 。
示例:
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
2. 思路解析
首先我们知道,队列是先进先出,栈是后进先出。
那么我们可以使用两个队列,始终保持一个队列为空。
当我们需要进行 压栈 操作时,将数据压入 不为空的队列中(若两个都为空,则随便压入一个队列)。如图所示
当需要进行 出栈 操作时,将 不为空的队列 中的数据导入 空队列 中,仅留下一个数据,这时将这个数据返回并且删除即可。
判断栈是否为空,即判断两个队列是否同时为空。
流程如图所示
3. 代码实现
队列的实现
typedef int QDataType;
// 链式结构:表示队列(记录每个结点)
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
// 队列的结构 (找到队列的头和尾的)
typedef struct Queue
{
QNode* head; // 队列的头指针
QNode* tail; // 队列的尾指针
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType x);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
//——————————————————————————————————————————————————————————————————————————
// 初始化队列
void QueueInit(Queue* q) {
assert(q); //队列可以为空,但是管理队列的头指针和尾指针不能为空
q->head = NULL;
q->tail = NULL;
}
// 队尾入队列(尾插)
void QueuePush(Queue* q, QDataType x) {
assert(q);
/*开辟一个新结点*/
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL) {
printf("malloc fail\n");
exit(-1);
}
newnode->data = x; //把x赋给newnode的数据域
newnode->next = NULL; //因为是尾插,所以尾部的结点的next要指向NULL
/*如果头、尾都为空,那么说明队列还是空的,还没有结点*/
if (q->head == NULL && q->tail == NULL) {
assert(q);
q->head = q->tail = newnode;
}
else {
//说明队列已经有结点了,直接到插入到尾部即可
q->tail->next = newnode; //把newnode链接到tail的next
q->tail = newnode; //然后让tail指向newnode
}
}
// 队头出队列
void QueuePop(Queue* q) {
assert(q);
assert(q->head && q->tail); //队列的head和tail不能为空,不然怎么头删呢?
//如果head的next为空,那么说明只有一个结点
if (q->head->next == NULL) {
free(q->head); //直接释放掉head
q->head = q->tail = NULL; //然后把head和tail 置为空
}
else {
QNode* next = q->head->next; //保存头结点的下一个结点地址
free(q->head); //释放掉head
q->head = next;
}
}
// 获取队列头部元素
QDataType QueueFront(Queue* q) {
assert(q);
assert(q->head); //取队头的数据,那么head肯定不能为空
return q->head->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q) {
assert(q);
assert(q->tail); //取队尾的数据,那么tail肯定不能为空
return q->tail->data;
}
// 获取队列中有效元素个数
// 这个函数是队列里面最慢的函数,时间复杂度为O(N)
int QueueSize(Queue* q) {
assert(q);
QNode* cur = q->head; //使用cur遍历整个队列
int count = 0; //统计队列元素个数
while (cur) {
//当cur不为空,就进入循环
count++;
cur = cur->next;
}
return count;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q) {
assert(q);
//如果head或者tail等于空,说队列为空
return q->head == NULL && q->tail == NULL;
}
// 销毁队列
void QueueDestroy(Queue* q) {
assert(q);
QNode* cur = q->head; //使用cur遍历整个队列
while (cur) {
//如果cur不为空
QNode* next = cur->next; //存储cur的下一个结点
free(cur); //释放掉cur
cur = next; //把cur的下一个结点赋给cur
}
q->head = q->tail = NULL;
}
接口代码
typedef struct
{
Queue q1;
Queue q2;
}MyStack;
MyStack* myStackCreate() {
MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
assert(pst);
QueueInit(&pst->q1);
QueueInit(&pst->q2);
return pst;
}
void myStackPush(MyStack* obj, int x) {
assert(obj);
/*判断q1和q2谁为空,谁为空就往谁里面去push*/
if (!QueueEmpty(&obj->q1)) {
QueuePush(&obj->q1, x);
}
else {
QueuePush(&obj->q2, x);
}
}
int myStackPop(MyStack* obj) {
assert(obj);
Queue* emptyQ = &obj->q1; //假设q1为空
Queue* nonEmptyQ = &obj->q2; //假设q2不为空
/*如果假设错误,那么就重新交换*/
if (!QueueEmpty(&obj->q1)) {
emptyQ = &obj->q2;
nonEmptyQ = &obj->q1;
}
/*把非空队列的前N个数据,导入空队列里面去,剩下一个删掉,就实现了后进先出*/
while (QueueSize(nonEmptyQ) > 1) {
int front = QueueFront(nonEmptyQ);
QueuePush(emptyQ, front); //把非空队列里面的队头的数据放到空里面去
QueuePop(nonEmptyQ); //删除队头的元素
}
// 此时还剩下一个,把他删掉
int top = QueueFront(nonEmptyQ);
QueuePop(nonEmptyQ);
return top;
}
int myStackTop(MyStack* obj) {
assert(obj);
/**/
if (!QueueEmpty(&obj->q1)) {
return QueueBack(&obj->q1);
}
else {
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
assert(obj);
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
assert(obj);
/*先销毁q1和q2*/
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
/** * 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); */
提交结果
边栏推荐
- R语言ggplot2可视化:使用ggpubr包的ggtexttable函数可视化表格数据(直接绘制表格图或者在图像中添加表格数据)、使用tbody_add_border为表格中的表头添加外侧框线
- 开箱即用-使用异步加载布局来优化页面启动速度的几种方案
- 字节跳动软件测试岗,收到offer后我却拒绝了~给面试的人一些忠告....
- 8年软件测试工程师的感悟:与薪资相匹配的永远是实力
- 多大数量级会出现哈希碰撞
- R language ggplot2 visualization: use the ggtexttable function of the ggpubr package to visualize tabular data (directly draw tabular graphs or add tabular data to images), use tbody_add_border to add
- R语言ggpubr包的ggline函数可视化分组折线图、add参数为mean_se和dotplot可视化不同水平均值的折线图并为折线图添加误差线(se标准误差)和点阵图、自定义palette设置颜色
- R语言ggplot2可视化:基于aes函数中的fill参数和shape参数自定义绘制分组折线图并添加数据点(散点)、使用theme函数的legend.position函数配置图例到图像右侧
- npm ERR! 400 Bad Request - PUT xxx - Cannot publish over previously published version “1.0.0“.
- LayaBox - TypeScript - merge statement
猜你喜欢
同样做软件测试,和月收入 3W 的学弟聊了一晚上,我彻底崩溃了
转转反爬攻防战
npm ERR! 400 Bad Request - PUT xxx - Cannot publish over previously published version “1.0.0“.
Hello, my new name is "Bronze Lock/Tongsuo"
DVWA 通关记录 2 - 命令注入 Command Injection
Com多进程通信实现
Alibaba CTO Cheng Li: Alibaba Open Source History, Concept and Practice
MySQL模糊查询性能优化
太帅了!我用炫酷大屏展示爬虫数据!
21年毕业转行软件测试,从0收入到月薪过万,我真的很幸运...
随机推荐
博云入选Gartner中国DevOps代表厂商
R语言时间序列数据的平滑:使用KernSmooth包的dpill函数和locpoly函数对时间序列数据进行平滑以消除噪声
The realization of the list
阿里云数据存储生态计划发布,助力伙伴数据创新
R语言ggplot2可视化:使用ggpubr包的ggbarplot函数可视化水平柱状图(条形图)、使用orientation参数设置柱状图转置为条形图
Alibaba CTO Cheng Li: Alibaba Open Source History, Concept and Practice
R语言时间序列数据算术运算:使用log函数将时间序列数据的数值对数化、使用diff函数计算对数化后的时间序列数据的逐次差分(计算价格的对数差分)
你认同这个观点吗?大多数企业的数字化都只是为了缓解焦虑
Smoothing of time series data in R language: smoothing time series data to remove noise using the dpill function and locpoly function of the KernSmooth package
循环结构--while循环
Geoffery Hinton: The Next Big Thing in Deep Learning
Spearman's correlation coefficient
Linux系统卸载,安装,升级,迁移clickHouse数据库
FPGA手撕代码——CRC校验码的多种Verilog实现方式 (2021乐鑫科技数字IC提前批代码编程)
The R language uses the rollapply function in the zoo package to apply the specified function to the time series in a rolling manner and the window moves, and set the align parameter to specify that t
Linux system uninstall, install, upgrade, migrate clickHouse database
阿里CTO程立:阿里巴巴开源的历程、理念和实践
学习笔记-支付宝支付
初探zend引擎
LayaBox---TypeScript---Module Analysis