当前位置: 首页 > news >正文

Leetcode 28

1 题目

225. 用队列实现栈

请你仅使用两个队列实现一个后入先出(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 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

输入:
["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

提示:

  • 1 <= x <= 9
  • 最多调用100 次 pushpoptop 和 empty
  • 每次调用 pop 和 top 都保证栈不为空

进阶:你能否仅用一个队列来实现栈。

2 题解

方法一:两个队列

要使用两个队列实现栈的功能,我们可以按照以下方式组织逻辑,其中queue1用于存储栈内元素,queue2作为入栈操作的辅助队列:

  1. 入栈操作

    • 先将新元素入队到queue2
    • queue1中所有元素依次出队并加入queue2
    • 交换queue1queue2的引用,使queue1始终存储栈内元素
    • 此时queue1的队首元素就是新入栈的元素(栈顶)
  2. 出栈操作

    • 直接移除并返回queue1的队首元素(栈顶元素)
  3. 获取栈顶元素

    • 返回queue1的队首元素但不移除
  4. 判断栈是否为空

    • 检查queue1是否为空

这种实现方式确保了每次入栈后,queue1的队首元素都是栈顶元素,符合栈 "后进先出" 的特性。

#define LEN 20
typedef struct queue {int *data;int head;int rear;int size;
} Queue;typedef struct {Queue *queue1, *queue2;
} MyStack;Queue *initQueue(int k) {Queue *obj = (Queue *)malloc(sizeof(Queue));obj->data = (int *)malloc(k * sizeof(int));obj->head = -1;obj->rear = -1;obj->size = k;return obj;
}void enQueue(Queue *obj, int e) {if (obj->head == -1) {obj->head = 0;}obj->rear = (obj->rear + 1) % obj->size;obj->data[obj->rear] = e;
}int deQueue(Queue *obj) {int a = obj->data[obj->head];if (obj->head == obj->rear) {obj->rear = -1;obj->head = -1;return a;}obj->head = (obj->head + 1) % obj->size;return a;
}int isEmpty(Queue *obj) {return obj->head == -1;
}MyStack *myStackCreate() {MyStack *obj = (MyStack *)malloc(sizeof(MyStack));obj->queue1 = initQueue(LEN);obj->queue2 = initQueue(LEN);return obj;
}void myStackPush(MyStack *obj, int x) {if (isEmpty(obj->queue1)) {enQueue(obj->queue2, x);} else {enQueue(obj->queue1, x);}
}int myStackPop(MyStack *obj) {if (isEmpty(obj->queue1)) {while (obj->queue2->head != obj->queue2->rear) {enQueue(obj->queue1, deQueue(obj->queue2));}return deQueue(obj->queue2);}while (obj->queue1->head != obj->queue1->rear) {enQueue(obj->queue2, deQueue(obj->queue1));}return deQueue(obj->queue1);
}int myStackTop(MyStack *obj) {if (isEmpty(obj->queue1)) {return obj->queue2->data[obj->queue2->rear];}return obj->queue1->data[obj->queue1->rear];
}bool myStackEmpty(MyStack *obj) {if (obj->queue1->head == -1 && obj->queue2->head == -1) {return true;}return false;
}void myStackFree(MyStack *obj) {free(obj->queue1->data);obj->queue1->data = NULL;free(obj->queue1);obj->queue1 = NULL;free(obj->queue2->data);obj->queue2->data = NULL;free(obj->queue2);obj->queue2 = NULL;free(obj);obj = NULL;
}

复杂度分析

时间复杂度

  • 入栈操作(push):O (n),其中 n 是栈内的元素个数。入栈时,需先将新元素加入 queue2,再将 queue1 中所有 n 个元素依次出队并加入 queue2,最后交换两个队列。整个过程共执行 2n+1 次操作(n 次出队、n+1 次入队),每次出队和入队的时间复杂度均为 O (1),因此整体时间复杂度为 O (n)。

  • 出栈操作(pop):O (1)。直接移除 queue1 的队首元素(栈顶元素),仅需一次出队操作。

  • 获取栈顶元素(top):O (1)。直接返回 queue1 的队首元素,无需修改队列内容。

  • 判断栈是否为空(empty):O (1)。只需检查 queue1 是否为空,无额外操作。

空间复杂度:O (n),其中 n 是栈内的元素个数。两个队列(queue1 和 queue2)共同存储栈中的所有元素,因此空间复杂度由元素总数决定。

方法二:一个队列

方法一使用了两个队列实现栈的操作,也可以使用一个队列实现栈的操作。

使用一个队列时,为了满足栈的特性,即最后入栈的元素最先出栈,同样需要满足队列前端的元素是最后入栈的元素。

入栈操作时,首先获得入栈前的元素个数 n,然后将元素入队到队列,再将队列中的前 n 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底。

由于每次入栈操作都确保队列的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以简单实现。

出栈操作只需要移除队列的前端元素并返回即可,获得栈顶元素操作只需要获得队列的前端元素并返回即可(不移除元素)。

由于队列用于存储栈内的元素,判断栈是否为空时,只需要判断队列是否为空即可。

typedef struct tagListNode {struct tagListNode* next;int val;
} ListNode;typedef struct {ListNode* top;
} MyStack;MyStack* myStackCreate() {MyStack* stk = calloc(1, sizeof(MyStack));return stk;
}void myStackPush(MyStack* obj, int x) {ListNode* node = malloc(sizeof(ListNode));node->val = x;node->next = obj->top;obj->top = node;
}int myStackPop(MyStack* obj) {ListNode* node = obj->top;int val = node->val;obj->top = node->next;free(node);return val;
}int myStackTop(MyStack* obj) {return obj->top->val;
}bool myStackEmpty(MyStack* obj) {return (obj->top == NULL);
}void myStackFree(MyStack* obj) {while (obj->top != NULL) {ListNode* node = obj->top;obj->top = obj->top->next;free(node);}free(obj);
}

3 详细解释

数据结构 05 栈和队列-CSDN博客https://blog.csdn.net/AYheyheyhey/article/details/153274912?spm=1001.2014.3001.5502

http://www.dtcms.com/a/486576.html

相关文章:

  • 【完整源码+数据集+部署教程】 【零售和消费品&存货】【无人零售】自动售卖机饮料检测系统源码&数据集全套:改进yolo11-KernelWarehouse
  • iOS框架内存中占用很高的ttc文件是否正常
  • 建设部网人事考试网站企业宣传片怎么拍
  • 料神wordpress建站教程优购物官方网站直播
  • Spring Boot 3零基础教程,yml语法细节,笔记16
  • 31-基于ZigBee的车位引导系统设计与实现
  • 济宁专业建网站seo关键词优化软件合作
  • 有赞商城建站优化收费
  • 石碣镇做网站晋城商城网站开发设计
  • AxonHub 开源程序是一个现代 AI 网关系统,提供统一的 OpenAI、Anthropic 和 AI SDK 兼容 API
  • 【运维心得】playbook远程清理windows亲测步骤
  • 【学习AI-相关路程-mnist手写数字分类-一段学习的结束:自我学习AI-复盘-代码-了解原理-综述(5) 】
  • 免费的cms视频网站模板3000款免费软件app下载
  • 网站模板没有html文件下载网站建设中忽略的字体侵权行为
  • QT学习和代码练习
  • 把 Python 应用打包成 Windows 可执行程序 — 完整指南
  • 阿里云代理商:什么是阿里云CDN配额?
  • 做推广任务的网站制作图片的软件加字体
  • 做公司网站优劣势成都建设网站那个好
  • vLLM 推理 AWQ 量化后的模型
  • **发散创新:游戏物理引擎的深入探究**一、引言随着游戏产业的飞速发展,游戏物理引擎作为游戏开发中不可或缺的一部分,
  • 上海网站制作网站wordpress 显示文章作者
  • QT 中的元对象系统(七):Q_GADGET 机制
  • 德阳做网站公司实体店线上线下运营模式
  • Agentlightning环境准备
  • 创建网站哪个好卫生计生加强门户网站建设
  • 申请建设活动中心网站管理咨询公司有哪些方面
  • Windows Server 2019 IP黑名单设置,保护云服务器安全
  • K8s存储-PV与PVC
  • k8s中PV 与 PVC