题目:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(
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提示:
1 <= x <= 9
- 最多调用
100
次push
、pop
、peek
和empty
- 假设所有操作都是有效的 (例如,一个空的队列不会调用
pop
或者peek
操作)进阶:
- 你能否实现每个操作均摊时间复杂度为
O(1)
的队列?换句话说,执行n
个操作的总时间复杂度为O(n)
,即使其中一个操作可能花费较长时间。
自己看到题目的第一想法
1. 栈是先进后出, 队列是先进先出, 这两个数据结构的操作逻辑是相反的.
2. 用栈模拟队列, 需要解决先进入的元素在栈底, 在出栈的时候拿不到栈底元素, 要怎么处理?
看完代码随想录之后的想法
因为栈是先进后出, 因此出栈和入栈的顺序是相反的. 也就是说如果有一个入栈顺序为 ABC...N 的串, 当我们把 ABC...N 从当前栈出栈后就可以得到 N...CBA 的串. 因此如果希望得到 ABC...N 的出栈顺序, 首先需要得到 N...CBA 的入栈串, 而 N...CBA 的入栈串则是 ABC...N 的出栈串.
因此我们可以用两个栈结构来模拟先进先出的顺序, 时间复杂度为O(n)
一开始也没想明白, 当使用双栈来模拟队列的时候, 如果发现输出栈为空, 就遍历输入栈的元素一个一个添加到输出栈中, 再弹出输出输出栈的第一个元素. 这样就将最早添加到输入栈中的元素弹出. 但是这时候为什么不需要把输出栈重新弹回输入栈中呢, 如果之后有新的输入, 当需要弹出的时候, 输入栈的元素弹出到输入栈, 不就导致更早加入输入栈中的元素, 被新的输入元素遮挡了吗? 后来想明白了, 当输出栈中有元素的时候, 是不可以把输入栈中的元素添加到输出栈中的. 这样就保证了顺序, 且不需要把输出栈中的元素倒回输入栈中.
class MyQueue {
private Stack<Integer> inStack = new Stack<>();
private Stack<Integer> outStack = new Stack<>();
public MyQueue() {
}
public void push(int x) {
inStack.push(x);
}
public int pop() {
if (outStack.isEmpty()) {
while (!inStack.isEmpty()) {
outStack.push(inStack.pop());
}
}
return outStack.pop();
}
public int peek() {
int result = pop();
outStack.push(result);
return result;
}
public boolean empty() {
return inStack.isEmpty() && outStack.isEmpty();
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
自己实现过程中遇到哪些困难
peek() 函数重新 push 的时候, 不是将元素添加到 inStack, 而是添加到 outStack, outStack 才是保证先进后出的栈.
题目:
请你仅使用两个队列实现一个后入先出(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
都保证栈不为空进阶:你能否仅用一个队列来实现栈。
自己看到题目的第一想法
先看视频再说~
看完代码随想录之后的想法
1. 队列是先进先出, 栈是先进后出. 只用一个队列, 怎么能拿到队列末尾的元素呢?
2. 哦, 原来可以把前 n - 1 个元素取出后顺序添加到队列末尾.
class MyStack {
private ArrayDeque<Integer> intQueue = new ArrayDeque<>();
public MyStack() {
}
public void push(int x) {
intQueue.add(x);
}
public int pop() {
int size = intQueue.size() - 1;
while (size-- > 0) {
intQueue.add(intQueue.remove());
}
return intQueue.remove();
}
public int top() {
return intQueue.getLast();
}
public boolean empty() {
return intQueue.isEmpty();
}
}
/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* boolean param_4 = obj.empty();
*/
自己实现过程中遇到哪些困难
对 Java 的队列不是很熟悉, 查了一下资料, 有 ArrayDeque(双向队列), LinkedList(连标实现的队列一样也是双向的).
Queue 和 Deque 都是接口, Queue 接口提供的是标准的队列添加、删除、获取三类方法, 其中每种方法失败时提供两种处理方式: 返回异常或者返回异常值.
Deque 提供了双向链表的接口定义. Queue 是不支持队首添加元素的, Deque 就添加了 addFirst() 方法, 其他还有 removeFirst()、getFirst() 等.
算法大部分时间是一个想法没有想到, 或者思路找到入口了, 但是一些细节没有想明白, 实现起来就会异常的困难. 但是说实话, 普通资质的人, 面对海量的算法题的时候, 又如何可能完全想的明白呢. 自己的想法是, 对于简单和真正中等难度的题目, 一定要掌握到细节, 能说的清楚说的明白. 对于中等偏上的题目, 要能说的清楚原理. 而对于原理中比较隐藏的循环、迭代部分, 需要知道对应的存在, 然而想不明白的话可以暂时忽略. 等之后再遇到的时候, 也许会有豁然开朗的时刻.