当前位置:网站首页>队列题目:用队列实现栈
队列题目:用队列实现栈
2022-08-09 18:26:00 【伟大的车尔尼】
题目
标题和出处
标题:用队列实现栈
出处:225. 用队列实现栈
难度
4 级
题目描述
要求
请你仅使用两个队列实现一个后进先出的栈。实现的栈应该支持普通栈的全部操作( push \texttt{push} push、 pop \texttt{pop} pop、 top \texttt{top} top 和 empty \texttt{empty} empty)。
实现 MyStack \texttt{MyStack} MyStack 类:
- void push(int x) \texttt{void push(int x)} void push(int x) 将元素 x \texttt{x} x 压入栈顶。
- int pop() \texttt{int pop()} int pop() 移除并返回栈顶元素。
- int top() \texttt{int top()} int top() 返回栈顶元素。
- boolean empty() \texttt{boolean empty()} boolean empty() 如果栈是空的,返回 true \texttt{true} true;否则,返回 false \texttt{false} false。
注意:
- 你只能使用队列的基本操作,只有在队尾添加元素、在队首查看和删除元素、返回元素个数和判断是否为空的操作是有效的。
- 你所使用的语言也许不支持队列。你可以使用列表或者双端队列来模拟一个队列,只要所有的操作都是标准的队列操作即可。
示例
示例 1:
输入:
["MyStack", "push", "push", "top", "pop", "empty"] \texttt{["MyStack", "push", "push", "top", "pop", "empty"]} ["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []] \texttt{[[], [1], [2], [], [], []]} [[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false] \texttt{[null, null, null, 2, 2, false]} [null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack(); \texttt{MyStack myStack = new MyStack();} MyStack myStack = new MyStack();
myStack.push(1); \texttt{myStack.push(1);} myStack.push(1);
myStack.push(2); \texttt{myStack.push(2);} myStack.push(2);
myStack.top(); \texttt{myStack.top();} myStack.top(); // 返回 2 \texttt{2} 2
myStack.pop(); \texttt{myStack.pop();} myStack.pop(); // 返回 2 \texttt{2} 2
myStack.empty(); \texttt{myStack.empty();} myStack.empty(); // 返回 False \texttt{False} False
数据范围
- 1 ≤ x ≤ 9 \texttt{1} \le \texttt{x} \le \texttt{9} 1≤x≤9
- 最多调用 100 \texttt{100} 100 次 push \texttt{push} push、 pop \texttt{pop} pop、 top \texttt{top} top 和 empty \texttt{empty} empty
- 每次调用 pop \texttt{pop} pop 和 top \texttt{top} top 都是有效的
进阶
你能否仅使用一个队列实现栈?
解法一
思路和算法
由于栈的特点是后进先出,因此使用队列实现栈时,需要维护队列内的元素顺序,使得队首元素是最后入队的元素。
使用两个队列实现时, queue 1 \textit{queue}_1 queue1 的作用是存储元素, queue 2 \textit{queue}_2 queue2 的作用是辅助操作。
为了实现栈的功能,需要保证每次入栈操作之后, queue 1 \textit{queue}_1 queue1 的队首元素总是新添加的元素。因此入栈操作如下:
将待添加的元素入队到 queue 2 \textit{queue}_2 queue2;
将 queue 1 \textit{queue}_1 queue1 的全部元素依次出队并入队到 queue 2 \textit{queue}_2 queue2;
将 queue 1 \textit{queue}_1 queue1 和 queue 2 \textit{queue}_2 queue2 互换。
完成上述操作后, queue 2 \textit{queue}_2 queue2 为空, queue 1 \textit{queue}_1 queue1 的队首元素是新添加的元素, queue 1 \textit{queue}_1 queue1 内的其余元素和顺序不变。因此上述操作的效果是在 queue 1 \textit{queue}_1 queue1 的队首增加了新添加的元素, queue 1 \textit{queue}_1 queue1 的队首和队尾分别对应栈顶和栈底。
由于每次入栈操作都维护了 queue 1 \textit{queue}_1 queue1 内的元素顺序,因此出栈操作和查看栈顶元素操作可以简单实现。出栈操作只需要将 queue 1 \textit{queue}_1 queue1 的队首元素移除并返回即可,查看栈顶元素操作只需要返回 queue 1 \textit{queue}_1 queue1 的队首元素即可。
由于 queue 1 \textit{queue}_1 queue1 的作用是存储元素,因此判断栈是否为空操作只需要判断 queue 1 \textit{queue}_1 queue1 是否为空即可。
代码
class MyStack {
Queue<Integer> queue1;
Queue<Integer> queue2;
public MyStack() {
queue1 = new ArrayDeque<Integer>();
queue2 = new ArrayDeque<Integer>();
}
public void push(int x) {
queue2.offer(x);
while (!queue1.isEmpty()) {
queue2.offer(queue1.poll());
}
Queue<Integer> temp = queue1;
queue1 = queue2;
queue2 = temp;
}
public int pop() {
return queue1.poll();
}
public int top() {
return queue1.peek();
}
public boolean empty() {
return queue1.isEmpty();
}
}
复杂度分析
时间复杂度:构造方法的时间复杂度是 O ( 1 ) O(1) O(1),入栈操作的时间复杂度是 O ( n ) O(n) O(n),出栈、查看栈顶元素和判断栈是否为空操作的时间复杂度都是 O ( 1 ) O(1) O(1),其中 n n n 是栈内元素个数。
入栈操作需要将 queue 1 \textit{queue}_1 queue1 的 n n n 个元素出队,并将 n + 1 n + 1 n+1 个元素入队到 queue 2 \textit{queue}_2 queue2,共有 2 n + 1 2n + 1 2n+1 次操作,每次出队和入队操作的时间复杂度都是 O ( 1 ) O(1) O(1),因此入栈操作的时间复杂度是 O ( n ) O(n) O(n)。
出栈、查看栈顶元素和判断栈是否为空操作都是常规队列操作,时间复杂度都是 O ( 1 ) O(1) O(1)。空间复杂度: O ( n ) O(n) O(n),其中 n n n 是栈内元素个数。需要使用队列存储元素。
解法二
思路和算法
也可以使用一个队列实现栈。
使用一个队列实现时,同样需要维护队列内的元素顺序,使得队首元素是最后入队的元素,因此需要保证每次入栈操作之后,队首元素总是新添加的元素。
使用一个队列实现的入栈操作和使用两个队列实现的入栈操作有所区别,由于只有一个队列,所有的元素都需要存储在队列内。入栈操作如下:
计算队列内的元素个数 size \textit{size} size;
将待添加的元素入队;
将队列内的前 size \textit{size} size 个元素依次出队并入队。
完成上述操作后,队首元素是新添加的元素,队列内的其余元素和顺序不变。因此上述操作的效果是在队首增加了新添加的元素,队首和队尾分别对应栈顶和栈底。
出栈操作、查看栈顶元素操作和判断栈是否为空操作和解法一相同,只需要在队列上执行相应操作即可。
代码
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue = new ArrayDeque<Integer>();
}
public void push(int x) {
int size = queue.size();
queue.offer(x);
for (int i = 0; i < size; i++) {
queue.offer(queue.poll());
}
}
public int pop() {
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
复杂度分析
时间复杂度:构造方法的时间复杂度是 O ( 1 ) O(1) O(1),入栈操作的时间复杂度是 O ( n ) O(n) O(n),出栈、查看栈顶元素和判断栈是否为空操作的时间复杂度都是 O ( 1 ) O(1) O(1),其中 n n n 是栈内元素个数。
入栈操作需要将队列的 n n n 个元素出队,并将 n + 1 n + 1 n+1 个元素入队,共有 2 n + 1 2n + 1 2n+1 次操作,每次出队和入队操作的时间复杂度都是 O ( 1 ) O(1) O(1),因此入栈操作的时间复杂度是 O ( n ) O(n) O(n)。
出栈、查看栈顶元素和判断栈是否为空操作都是常规队列操作,时间复杂度都是 O ( 1 ) O(1) O(1)。空间复杂度: O ( n ) O(n) O(n),其中 n n n 是栈内元素个数。需要使用队列存储元素。
边栏推荐
猜你喜欢

golang单元测试:testing包的基本使用

一些自动化测试01

qq机器人账号不能发送群消息,被风控
![[免费专栏] Android安全之Xposed插件开发【从零手把手带】教程](/img/7b/a036ac664c7e27ed7d87e7ee18c05d.png)
[免费专栏] Android安全之Xposed插件开发【从零手把手带】教程

日本著名设计师三宅一生去世:产品曾被国人高价抢 乔布斯也是粉丝

Codesys结构变量编程应用(STRUCT类型)

Fully automated machine learning modeling!The effect hangs the primary alchemist!

论文精读:VIT - AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE

字节二面,差点倒在了MySQL上面

Bi Sheng Compiler Optimization: Lazy Code Motion
随机推荐
正则表达式(全)
放下手机吧:实验表明花20分钟思考和上网冲浪同样快乐
软件设计的七大原则
单片机编程-状态机
优秀的 Verilog/FPGA开源项目介绍(三十一)- OFDM
[Free Column] Android Security for Peace Elite (FZ) APK Reverse Analysis
【知识点合辑】numpy常用函数+jupyter小用法
史上最全架构师知识图谱(纯干货)
2022了你还不会『低代码』?数据科学也能玩转Low-Code啦!
基于CC2530 E18-MS1-PCB Zigbee DIY作品
YOLO v3 source, rounding
[免费专栏] Android安全之和平精英(FZ)APK逆向分析
国产抗新冠口服药每瓶不超300元/ 我国IPv6网络全面建成/ 谷歌入局折叠屏手机...今日更多新鲜事在此...
没有 accept,建立 TCP 连接,可以吗?
shell脚本基础语句使用(一)
MFC教程
Bi Sheng Compiler Optimization: Lazy Code Motion
WPF 实现带蒙版的 MessageBox 消息提示框
字节二面,差点倒在了MySQL上面
单调栈