当前位置:网站首页>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); */
提交结果
边栏推荐
猜你喜欢
【面向校招】Golang面试题合集
DVWA Clearance Log 2 - Command Injection
After 21 years of graduation, I switched to software testing. From 0 income to a monthly salary of over 10,000, I am really lucky...
阿里CTO程立:阿里巴巴开源的历程、理念和实践
你认同这个观点吗?大多数企业的数字化都只是为了缓解焦虑
Why use BGP?
iNFTnews | Seeing the two sides of the metaverse, what is the true Internet and the Internet of value?
Three.JS程序化建模入门
8年软件测试工程师的感悟:与薪资相匹配的永远是实力
Shell脚本实现多选DNS同时批量解析域名IP地址(新更新)
随机推荐
logo 图标(php图片加文字水印)
众城优选系统开发功能
全方位剖析Numpy中的np.diag源代码
R语言时间序列数据的平滑:使用KernSmooth包的dpill函数和locpoly函数对时间序列数据进行平滑以消除噪声
【面向校招】Golang面试题合集
The R language uses the ggtexttable function of the ggpubr package to visualize the table data (draw the table directly or add the table data to the image), set the theme parameter to customize the fi
Alibaba CTO Cheng Li: Alibaba Open Source History, Concept and Practice
Why use BGP?
如何安装dosbox(pycharm详细安装教程)
基于列表的排队与叫号系统
Rear tube implements breadcrumb function
21年毕业转行软件测试,从0收入到月薪过万,我真的很幸运...
初探zend引擎
LayaBox---TypeScript---Namespaces and modules
R语言时间序列数据算术运算:使用log函数将时间序列数据的数值对数化、使用diff函数计算对数化后的时间序列数据的逐次差分(计算价格的对数差分)
Verilog的随机数系统任务----$random
R语言ggpubr包的ggbarplot函数可视化分组柱状图、设置add参数为mean_se可视化不同水平均值的柱状图并为柱状图添加误差线(se标准误差)、position参数自定义分组柱状图分离
yolov7创新点
只问耕耘,不问收获,其实收获却在耕耘中
LayaBox---TypeScript---Decorator