代码随想录算法训练营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的值,这些值如下:

其它所有值都是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

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值