Implement the following operations of a stack using queues.
- push(x) — Push element x onto stack.
- pop() — Removes the element on top of the stack.
- top() — Get the top element.
- empty() — Return whether the stack is empty.
Example:
MyStack stack = new MyStack(); stack.push(1); stack.push(2); stack.top(); // returns 2 stack.pop(); // returns 2 stack.empty(); // returns false
Notes:
- You must use only standard operations of a queue — which means only
push to back
,peek/pop from front
,size
, andis empty
operations are valid. - Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.
- You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and all test cases.
这道题让我们用队列来实现栈,队列和栈作为两种很重要的数据结构,它们最显著的区别就是,队列是先进先出,而栈是先进后出。题目要求中又给定了限制条件只能用queue的最基本的操作,像back()这样的操作是禁止使用的。那么怎么样才能让先进先出的特性模拟出先进后出呢,这里就需要另外一个队列来辅助操作,我们总共需要两个队列,其中一个队列用来放最后加进来的数,模拟栈顶元素。剩下所有的数都按顺序放入另一个队列中。当push操作时,将新数字先加入模拟栈顶元素的队列中,如果此时队列中有数字,则将原本有的数字放入另一个队中,让新数字在这队中,用来模拟栈顶元素。当top操作时,如果模拟栈顶的队中有数字则直接返回,如果没有则到另一个队列中通过平移数字取出最后一个数字加入模拟栈顶的队列中。当pop操作时,先执行下top()操作,保证模拟栈顶的队列中有数字,然后再将该数字移除即可。当empty操作时,当两个队列都为空时,栈为空。代码如下:
解法一:
class MyStack { public: /** Initialize your data structure here. */ MyStack() {} /** Push element x onto stack. */ void push(int x) { q2.push(x); while (q2.size() > 1) { q1.push(q2.front()); q2.pop(); } } /** Removes the element on top of the stack and returns that element. */ int pop() { int x = top(); q2.pop(); return x; } /** Get the top element. */ int top() { if (q2.empty()) { for (int i = 0; i < (int)q1.size() - 1; ++i) { q1.push(q1.front()); q1.pop(); } q2.push(q1.front()); q1.pop(); } return q2.front(); } /** Returns whether the stack is empty. */ bool empty() { return q1.empty() && q2.empty(); } private: queue<int> q1, q2; };
这道题还有另一种解法,可以参见另一道类似的题Implement Queue using Stacks 用栈来实现队列,我个人来讲比较偏爱下面这种方法,比较好记,只要实现对了push函数,后面三个直接调用队列的函数即可。这种方法的原理就是每次把新加入的数插到前头,这样队列保存的顺序和栈的顺序是相反的,它们的取出方式也是反的,那么反反得正,就是我们需要的顺序了。我们需要一个辅助队列tmp,把s的元素也逆着顺序存入tmp中,此时加入新元素x,再把tmp中的元素存回来,这样就是我们要的顺序了,其他三个操作也就直接调用队列的操作即可,参见代码如下:
解法二:
class MyStack { public: /** Initialize your data structure here. */ MyStack() {} /** Push element x onto stack. */ void push(int x) { q.push(x); for (int i = 0; i < (int)q.size() - 1; ++i) { q.push(q.front()); q.pop(); } } /** Removes the element on top of the stack and returns that element. */ int pop() { int x = q.front(); q.pop(); return x; } /** Get the top element. */ int top() { return q.front(); } /** Returns whether the stack is empty. */ bool empty() { return q.empty(); } private: queue<int> q; };
讨论:上面两种解法对于不同的输入效果不同,解法一花在top()函数上的时间多,所以适合于有大量push操作,而top和pop比较少的输入。而第二种解法在push上要花大量的时间,所以适合高频率的top和pop,较少的push。两种方法各有千秋,互有利弊。
类似题目:
参考资料:
https://leetcode.com/problems/implement-stack-using-queues/
https://leetcode.com/problems/implement-stack-using-queues/discuss/62527/A-simple-C%2B%2B-solution