个人技术分享

题目表述

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

  • 你只能使用队列的标准操作 —— 也就是 push to backpeek/pop from frontsize 和 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 次 pushpoptop 和 empty
  • 每次调用 pop 和 top 都保证栈不为空

进阶:你能否仅用一个队列来实现栈。

力扣链接

leetcode225

思路分析

题目要求使用两个队列来实现栈的基本功能,上一题我们做了使用两个栈来实现队列的基本功能,这题是相反的。我们的解题方案可以有两种:1.用两个队列来实现,2.用一个队列来实现。我们重点讲一下第二种方案。

首先push方法实现起来非常简单,直接append就可以。然后就是重点的pop方法,这个方法,栈和队列有很大的区别,栈是先进后出,而队列是先进先出,要想用队列实现先进后出,就必须每次pop之前将左边的n-1个元素移除开然后逐个添加到右边,具体操作可以看下面pop方法中的for循环。

top方法的实现与pop大部分类似,不过就是top还需要保持队列的内容不变。

代码分析

# 方法一,用一个队列来实现
class MyStack:

    def __init__(self):
        # deque是python的双向队列,类似list,可以快速在队列的头部和尾部添加或删除元素
        self.que = deque()

    # 这个方法用来实现元素添加
    def push(self, x: int) -> None:
        # 从右端添加元素。如果从左端添加应使用appendleft()函数
        self.que.append(x)

    # 这个方法用来实现元素移除,这是关键,使用队列来实现栈
    def pop(self) -> int:
        # 判断队列是否为空
        if self.empty():
            return None
        # 移除队列左边的元素,然后添加到队列右边,循环这个操作共n-1次,将最右边那个元素弄到最左边去。
        for i in range(len(self.que)-1):
            self.que.append(self.que.popleft())
        # 移除最左边的元素
        return self.que.popleft()


    def top(self) -> int:
        if self.empty():
            return None
        # 与pop方法中的转换方式相同
        for i in range(len(self.que)-1):
            self.que.append(self.que.popleft())
        # 获取最左边的元素
        temp = self.que.popleft()
        # 将刚刚popleft掉的元素添加回去最右边,还原队列
        self.que.append(temp)
        return temp


    def empty(self) -> bool:
        return not self.que



# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()




# 方法2,用两个队列来实现。
from collections import deque

class MyStack:

    def __init__(self):
        """
        Python普通的Queue或SimpleQueue没有类似于peek的功能
        也无法用索引访问,在实现top的时候较为困难。

        用list可以,但是在使用pop(0)的时候时间复杂度为O(n)
        因此这里使用双向队列,我们保证只执行popleft()和append(),因为deque可以用索引访问,可以实现和peek相似的功能

        in - 存所有数据
        out - 仅在pop的时候会用到
        """
        self.queue_in = deque()
        self.queue_out = deque()

    def push(self, x: int) -> None:
        """
        直接append即可
        """
        self.queue_in.append(x)


    def pop(self) -> int:
        """
        1. 首先确认不空
        2. 因为队列的特殊性,FIFO,所以我们只有在pop()的时候才会使用queue_out
        3. 先把queue_in中的所有元素(除了最后一个),依次出列放进queue_out
        4. 交换in和out,此时out里只有一个元素
        5. 把out中的pop出来,即是原队列的最后一个
        
        tip:这不能像栈实现队列一样,因为另一个queue也是FIFO,如果执行pop()它不能像
        stack一样从另一个pop(),所以干脆in只用来存数据,pop()的时候两个进行交换
        """
        if self.empty():
            return None

        for i in range(len(self.queue_in) - 1):
            self.queue_out.append(self.queue_in.popleft())
        
        self.queue_in, self.queue_out = self.queue_out, self.queue_in    # 交换in和out,这也是为啥in只用来存
        return self.queue_out.popleft()

    def top(self) -> int:
        """
        写法一:
        1. 首先确认不空
        2. 我们仅有in会存放数据,所以返回第一个即可(这里实际上用到了栈)
        写法二:
        1. 首先确认不空
        2. 因为队列的特殊性,FIFO,所以我们只有在pop()的时候才会使用queue_out
        3. 先把queue_in中的所有元素(除了最后一个),依次出列放进queue_out
        4. 交换in和out,此时out里只有一个元素
        5. 把out中的pop出来,即是原队列的最后一个,并使用temp变量暂存
        6. 把temp追加到queue_in的末尾
        """
        # 写法一:
        # if self.empty():
        #     return None
        
        # return self.queue_in[-1]    # 这里实际上用到了栈,因为直接获取了queue_in的末尾元素

        # 写法二:
        if self.empty():
            return None

        for i in range(len(self.queue_in) - 1):
            self.queue_out.append(self.queue_in.popleft())
        
        self.queue_in, self.queue_out = self.queue_out, self.queue_in 
        temp = self.queue_out.popleft()   
        self.queue_in.append(temp)
        return temp


    def empty(self) -> bool:
        """
        因为只有in存了数据,只要判断in是不是有数即可
        """
        return len(self.queue_in) == 0