代码随想录算法训练营day10 | 232.用栈实现队列、225. 用队列实现栈

python相关的栈与队列了解

  • list的一些方法 https://www.geeksforgeeks.org/list-methods-python/
  • 双端队列deque https://www.geeksforgeeks.org/deque-in-python/
  • 和C++不同,Python没有实现栈和队列特定的类,可以是使用list和deque实现 https://www.geeksforgeeks.org/stack-and-queues-in-python/
  • 在使用list实现stack时,添加元素(append)和删除(pop)元素都是很高效的O(1);而在使用list实现queue时,删除(pop(0))元素时间复杂度为O(n),添加(append)元素还是O(1)
  • 在使用deque实现stack时,和list一样高效,append和pop;在使用deque实现queue时,添加和删除元素(append和popleft)的时间复杂度还是O(1),比list高效

In case of stack, list implementation works fine and provides both append() and pop() in O(1) time. When we use deque implementation, we get same time complexity.

But when it comes to queue, the above list implementation is not efficient. In queue when pop() is made from the beginning of the list which is slow. This occurs due to the properties of list, which is fast at the end operations but slow at the beginning operations, as all other elements have to be shifted one by one.

So, we prefer the use of dequeue over list, which was specially designed to have fast appends and pops from both the front and back end.

Python实现stack更多方法:https://www.geeksforgeeks.org/stack-in-python/?ref=ml_lbp

Python实现queue更多方法:https://www.geeksforgeeks.org/queue-in-python/?ref=ml_lbp

简洁的概括:https://juejin.cn/s/stack%20and%20queue%20in%20python

232.用栈实现队列

下面的代码通过了,但是deque为空的判断还有疑惑,比如deque中元素为空了,但是使用is None判断是False,那为啥使用if XX 进行判断的时候可以准确知道还有没有元素?

if x: #x is treated True except for all empty data types [],{},(),'',0 False, and None

if x is not None # which works only on None

参考文档:https://stackoverflow.com/questions/7816363/if-a-vs-if-a-is-not-none

if x 用来判断x是True还是False,与None无关。而Python中事先定义了一些为False的值,这些值如下:

代码随想录算法训练营day10 | 232.用栈实现队列、225. 用队列实现栈_第1张图片

其它所有值都是True。而if x is None则是判断x是否为None

文档:https://bobbyhadz.com/blog/python-check-if-none

这个文档中还提到的小知识:判断是否为None的时候用is或者is not,is相当于判断引用地址是否一样,None在Python中是唯一的。==符号调用了equal函数,判断的是值是否一样。id()可以查看Python在cpython内存空间上的地址

题目保证了每次调用都不可能为空,所以不用进行空的判断

class MyQueue:

    def __init__(self):
        # 队列的初始化按照题目要求有两个栈
        from collections import deque
        self.stack1 = deque()
        self.stack2 = deque()

    def push(self, x: int) -> None:
        self.stack1.append(x)

    def pop(self) -> int:
        # 如果stack2不为空,则可以直接弹出栈顶元素。否则需要stack1导入stack2
        if self.stack2:
            return self.stack2.pop()
        else:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        return self.stack2.pop()

    def peek(self) -> int:
        if self.stack2:
            return self.stack2[-1]
        else:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        return self.stack2[-1]

    def empty(self) -> bool:
        if len(self.stack1) == 0 and len(self.stack2) == 0:
            return True
        else:
            return False

为空的代码也可以改为下面这样:

def empty(self) -> bool:
    if not self.stack1 and not self.stack2:
        return True
    else:
        return False

看了代码之后发现的小技巧:pop和peek代码重复了一部分,可以复用,以后改进吧

225. 用队列实现栈

一、两个队列模拟栈

和两个栈模拟队列差别有点大,两个队列模拟栈得倒腾两次才行,在模拟pop操作的时候,需要把一个队列的元素只保留一个,其它的移到另一个辅助队列,在得到这个保留的元素之后,主队列赋值为辅助队列的值。

关于Python语言的又一个注意点出现了,在一个队列赋值给另一个队列的时候,这个时候赋值的是引用,可以看下面的代码

print(id(self.queue1), id(self.queue2)) 
self.queue1 = self.queue2 
print(id(self.queue1), id(self.queue2))

代码如下

class MyStack:

    def __init__(self):
        # 按照题目要求初始化两个队列
        from collections import deque
        self.queue1 = deque()
        self.queue2 = deque()  # 辅助队列

    def push(self, x: int) -> None:
        self.queue1.append(x)

    def pop(self) -> int:
        # 将队列1中的元素只保留一个,其它的都放到队列2
        for _ in range(len(self.queue1)-1):
            self.queue2.append(self.queue1.popleft())
        res = self.queue1.popleft()
        # 重新恢复原状
        self.queue1, self.queue2 = self.queue2, self.queue1
        while self.queue2:
            self.queue2.popleft()

        return res

    def top(self) -> int:
        # 将队列1中的元素只保留一个,其它的都放到队列2
        for _ in range(len(self.queue1) - 1):
            self.queue2.append(self.queue1.popleft())
        res = self.queue1.popleft()
        # 重新恢复原状
        self.queue1, self.queue2 = self.queue2, self.queue1
        while self.queue2:
            self.queue2.popleft()

        self.queue1.append(res)
        return res

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


注:上面的代码在改变两个队列交换方式之后可优化

二、一个队列模拟栈

只要在弹出元素的时候保留最后一个元素,将其它弹出元素放在同一个队列中就行。比两个队列的实现更方便

class MyStack:

    def __init__(self):
        # 一个队列
        from collections import deque
        self.queue = deque()

    def push(self, x: int) -> None:
        self.queue.append(x)

    def pop(self) -> int:
        for _ in range(len(self.queue)-1):
            self.queue.append(self.queue.popleft())
        return self.queue.popleft()

    def top(self) -> int:
        for _ in range(len(self.queue) - 1):
            self.queue.append(self.queue.popleft())
        res = self.queue.popleft()
        self.queue.append(res)
        return res

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

你可能感兴趣的:(代码随想录,算法)