题目描述
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:
你只能使用队列的标准操作 —— 也就是 push to back、peek/pop from front、size 和 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 次 push、pop、top 和 empty
- 每次调用 pop 和 top 都保证栈不为空
进阶:你能否仅用一个队列来实现栈。
解题思路
栈的特性是后进先出(LIFO),而队列的特性是先进先出(FIFO)。
最开始的思路,就是用队列来存储数据,然后每次 pop
的时候,将队列中的元素全部出队,最后一个出队的元素就是栈顶元素。同时出队的元素重新入队到辅助队列中。这样就能实现栈的特性。
1 | type MyStack struct { |
上面的代码使用双队列来实现栈的功能,每次 push
就正常地将元素入队,而每次 pop
和 top
都需要遍历整个队列,将元素出队并重新入队,时间复杂度为 O(n)。其中 pop
的操作中,最后一个元素出队后不再压入新队列中。
基于上面的思路,用一个队列也能完成。上面使用的双队列是因为每次出队后要把元素重新入对,最后将新队列赋值给原队列。实际上,我们可以在 push
的时候就将新元素放到队列的前面,这样在 pop
和 top
的时候就不需要再申请一块空间用于存放原队列的元素了。
1 | type MyStack struct { |
代码中需要注意的是,从队列中出队的次数是基于开始时队列的元素个数,而随着每次出队操作后,队列的元素个数会减少,所以在 pop
和 top
的时候需要使用一个变量来记录开始时队列的长度。