题目描述
- [225]仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)
- [232]仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)
一、个人拙见
对比队列与栈的特性区别,一个是先进先出,一个是先进后出,然后,嗯~ o( ̄▽ ̄)o!
用栈实现队列
class MyQueue {
Stack<Integer> s1;
Stack<Integer> s2;
public MyQueue() {
s1 = new Stack<Integer>();
s2 = new Stack<Integer>();
}
/**
* Push element x to the back of queue.
*/
public void push(int x) {
s1.push(x);
}
/**
* Removes the element from in front of queue and returns that element.
*/
public int pop() {
peek();
return s2.pop();
}
/**
* Get the front element.
*/
public int peek() {
if (s2.isEmpty()) {
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
}
if (s2.isEmpty()) {
return -1;
} else {
return s2.peek();
}
}
/**
* Returns whether the queue is empty.
*/
public boolean empty() {
return s1.isEmpty() && s2.isEmpty();
}
}
用队列实现栈
class MyStack {
Queue<Integer> q1, q2;
public MyStack() {
q1 = new LinkedList<>();
q2 = new LinkedList<>();
}
/**
* Push element x onto stack.
*/
public void push(int x) {
q1.add(x);
}
/**
* Removes the element on top of the stack and returns that element.
*/
public int pop() {
top();
return q1.remove();
}
/**
* Get the top element.
*/
public int top() {
if (q1.isEmpty()) {
while (!q2.isEmpty()) {
q1.add(q2.remove());
}
}
if (q1.isEmpty()) return -1;
while (q1.size() > 1) {
q2.add(q1.remove());
}
return q1.peek();
}
/**
* Returns whether the stack is empty.
*/
public boolean empty() {
return q1.isEmpty() && q2.isEmpty();
}
}
二、labuladong解答
作者:labuladong
这位大牛的方法,只用了一个队列实现。确实,脑袋被前一道题限制了,以为还是要用俩队列。。。
且用了个变量,存储top
class MyStack {
Queue<Integer> q = new LinkedList<>();
int topElem = 0;
public void push(int x) {
// x 是队列的队尾,是栈的栈顶
q.offer(x);
topElem = x;
}
public int top() {
return topElem;
}
public int pop() {
int size = q.size();
// 留下队尾 2 个元素
while (size > 2) {
q.offer(q.poll());
--size;
}
// 记录新的队尾元素
// 此时的位置即为删除最后元素后的新的最后元素
topElem = q.peek();
q.offer(q.poll());
// 删除之前的队尾元素
return q.poll();
}
public boolean empty() {
return q.isEmpty();
}
}
三、官方解答
解法一、两个队列
思路
为了满足栈的特性,即最后入栈的元素最先出栈,在使用队列实现栈时,应满足队列前端的元素是最后入栈的元素。可以使用两个队列实现栈的操作,其中 queue 1 用于存储栈内的元素,queue 2 作为入栈操作的辅助队列。
入栈操作时,首先将元素入队到 queue 2 ,然后将 queue 1 的全部元素依次出队并入队到 queue 2 ,此时 queue 2 的前端的元素即为新入栈的元素,再将 queue 1 和 queue 2 互换,则 queue 1 的元素即为栈内的元素,queue 1 的前端和后端分别对应栈顶和栈底。
代码
class MyStack {
Queue<Integer> queue1;
Queue<Integer> queue2;
/** Initialize your data structure here. */
public MyStack() {
queue1 = new LinkedList<Integer>();
queue2 = new LinkedList<Integer>();
}
/** Push element x onto stack. */
public void push(int x) {
queue2.offer(x);
while (!queue1.isEmpty()) {
queue2.offer(queue1.poll());
}
Queue<Integer> temp = queue1;
queue1 = queue2;
queue2 = temp;
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue1.poll();
}
/** Get the top element. */
public int top() {
return queue1.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue1.isEmpty();
}
}
复杂度分析
- 时间复杂度:入栈操作 O(n),其余操作都是 O(1)。
- 空间复杂度:O(n),其中 n 是栈内的元素。需要使用两个队列存储栈内的元素。
解法二、一个队列
思路
使用一个队列时,为了满足栈的特性,即最后入栈的元素最先出栈,同样需要满足队列前端的元素是最后入栈的元素。
入栈操作时,首先获得入栈前的元素个数 n,然后将元素入队到队列,再将队列中的前 n 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底。
代码
class MyStack {
Queue<Integer> queue;
/** Initialize your data structure here. */
public MyStack() {
queue = new LinkedList<Integer>();
}
/** Push element x onto stack. */
public void push(int x) {
int n = queue.size();
queue.offer(x);
for (int i = 0; i < n; i++) {
queue.offer(queue.poll());
}
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue.poll();
}
/** Get the top element. */
public int top() {
return queue.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue.isEmpty();
}
}
复杂度分析
- 时间复杂度:入栈操作 O(n),其余操作都是 O(1)。
- 空间复杂度:O(n),其中 n 是栈内的元素。需要使用一个队列存储栈内的元素。