力扣 232题 用栈实现队列

103 阅读3分钟

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 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

思路:队列数据进入的顺序是先进先出

4aee8dee00c1b051386b739353082d5.jpg 从右侧进入,从左侧出来。

再来看看堆栈的入栈顺序:

515b182781af011c464af9b7dd020a7.jpg 可以看到堆栈的数据顺序和队列的数据顺序是反的,那么只需要将该栈中的数据从上到下存入另一个栈中,这样数据的顺序就和队列的顺序相同了,这一点题目已经给了很明显的提示了,也很好想到,有时候可能会想不出来,很大程度是因为没有画图,再看完代码随想录中的动态图后,你会发现真的很好理解。

8e2861f571017a1d11a006a8b594690.jpg 现在只需要对第二个栈进行弹出操作便可以得到队列出对的第一个数据。

代码如下:

image.png image.png 但是在写代码的时候有几点是需要考虑清楚的,我在对队列进行push操作时,将数据push进了第一个堆栈,那么我什么时候将数据翻转到第二个堆栈呢?

1.在stack1!不为空的时候,也就是每一次push完了一堆数据后,进行pop或peek操作时将stack1翻转到stack2; 可以预见的是,只有一种情况可以通过,也就是在push完数据后,不再进行push操作。

情况如下: 先进行两次push操作,那么stack1中有两个数据,然后进行pop或push,那么现在因为stack1不为空,然后将stack1数据翻转给stack2,然后stack1为空,设stack2中数据为[1,2],也即队列为[1,2],如果接下来只进行pop或peek操作,那么只需要对stack2进行相应操作即可获得对应数据。如果在进行一次pop后,stack2和对列均变为[2],如果这时进行push操作,push一个3进来,那么队列变为:[2,3],此时因为stack1不为空,所以要把stack1中的数据翻转到stack2中,也就是stack2变为[3,2]这样就和队列不相同了。

所以当stack2为空时,才需要将stack1中的数据翻转至stack2中,对于后来的push操作,保存至stack1中,直到stacks进行pop操作将所有数据输出,为空时才重新传入stack1中的数据。

我的逻辑思维不太好,上述描述均为自己的理解,但是说不出来,很模糊,说白了就是想明白什么时候需要将stack1传入stack2中。

还有一点就是判断堆栈是否为空,不能使用stack == null这样的判断条件,需要使用if(stack.empty()); 如果不为空,在语句前加上否即可:if(!stack.empty()); 还有一种就是stack的大小为0:if(stack.size()==0);