225.用队列实现栈
请你仅使用两个队列实现一个后入先出(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
都保证栈不为空
步骤解释:
-
初始化:创建两个空队列
queue1
和queue2
。 -
Push 操作:
- 将要添加的元素
x
先放入辅助队列queue2
。 - 然后,将
queue1
中的所有元素依次出队并入队到queue2
,这样queue2
中的元素顺序与原queue1
相反,即最后一个元素现在在queue2
的前面。 - 最后,交换
queue1
和queue2
的引用,使得queue1
现在包含了所有元素,且顺序与栈的结构一致。
- 将要添加的元素
-
Pop 操作:由于
queue1
现在包含了所有元素,且顺序与栈一致,所以可以直接从queue1
的前面移除并返回元素。 -
Top 操作:返回
queue1
的第一个元素,即栈顶元素,但不移除它。 -
Empty 操作:检查
queue1
是否为空。
初始状态: queue1: [] queue2: []
步骤1: 将新元素放入 queue2: queue1: [] queue2: [x]
步骤2: 将 queue1 中的所有元素转移到 queue2: queue1: [] queue2: [x, ...原本 queue1 中的所有元素]
步骤3: 交换 queue1 和 queue2 的引用: queue1: [x, ...原本 queue1 中的所有元素] queue2: []
这个过程的核心在于,通过交换队列和重新排队,我们能够以队列的结构来模拟栈的行为
class MyStack {
Queue<Integer> queue1; // 和栈中保持一样元素的队列
Queue<Integer> queue2; // 辅助队列
/** Initialize your data structure here. */
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
/** Push element x onto stack. */
public void push(int x) {
queue2.offer(x); // 先放在辅助队列中
while (!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
Queue<Integer> queueTemp;
queueTemp = queue1;
queue1 = queue2;
queue2 = queueTemp; // 最后交换queue1和queue2,将元素都放到queue1中
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue1.poll(); // 因为queue1中的元素和栈中的保持一致,所以这个和下面两个的操作只看queue1即可
}
/** Get the top element. */
public int top() {
return queue1.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue1.isEmpty();
}
}
232、用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(
push
、pop
、peek
、empty
):实现
MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回true
;否则,返回false
说明:
- 你 只能 使用标准的栈操作 —— 也就是只有
push to top
,peek/pop from top
,size
, 和is empty
操作是合法的。- 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
示例 1:
输入: ["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 1, 1, false] 解释: MyQueue myQueue = new MyQueue(); myQueue.push(1); // queue is: [1] myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue) myQueue.peek(); // return 1 myQueue.pop(); // return 1, queue is [2] myQueue.empty(); // return false
初始状态
inStack: []
outStack: []
步骤1: push(1)
inStack: [1]
outStack: []
步骤2: push(2)
inStack: [2, 1]
outStack: []
步骤3: peek()
由于outStack
为空,我们需要调用in2out()
方法来转移元素:
inStack: []
outStack: [1, 2]
现在我们可以查看队列的前端元素,即outStack
的栈顶元素:
peek(): 1
步骤4: pop()
inStack: []
outStack: [2]
我们从outStack
中弹出一个元素:
pop(): 1
步骤5: push(3)
inStack: [3]
outStack: [2]
步骤6: pop()
此时outStack
不为空,我们可以直接弹出元素:
inStack: [3]
outStack: []
pop(): 2
步骤7: pop()
由于outStack
又为空了,我们需要再次调用in2out()
方法:
inStack: []
outStack: [3]
然后弹出元素:
pop(): 3
步骤8: empty()
现在两个栈都为空,所以队列为空:
inStack: []
outStack: []
empty(): true
通过这个例子,我们可以看到MyQueue
是如何通过两个栈来模拟队列行为的。每当需要出队操作时,如果outStack
为空,我们就将inStack
中的元素全部转移到outStack
中,这样就可以保证元素的出队顺序是正确的。而在入队操作时,我们总是将元素直接压入inStack
,这样可以保持入队操作的高效性。这种设计使得队列的入队操作平均时间为O(1),而出队操作的摊还时间也是O(1)。
class MyQueue {
Deque<Integer> inStack;
Deque<Integer> outStack;
public MyQueue() {
inStack = new ArrayDeque<Integer>();
outStack = new ArrayDeque<Integer>();
}
public void push(int x) {
inStack.push(x);
}
public int pop() {
if (outStack.isEmpty()) {
in2out();
}
return outStack.pop();
}
public int peek() {
if (outStack.isEmpty()) {
in2out();
}
return outStack.peek();
}
public boolean empty() {
return inStack.isEmpty() && outStack.isEmpty();
}
private void in2out() {
while (!inStack.isEmpty()) {
outStack.push(inStack.pop());
}
}
}