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

栈与队列

理论基础

  • 栈 (stack) :所有元素必须符合后进先出(LIFO)规则
  • 队列 (queue):所有元素必须符合先进先出(FIFO)规则

常用 api

list.pop(index) 会返回 list[index],同时在 list 内删除 index 对应的元素
list.pop() 默认弹出最后一个元素

deque

deque 是 python collections 中的子类,具体表现为两端队列
deque 可以有效处理 list 中特定操作复杂度过高的情况。

from collections import deque

deque讲解
api详细举例

以下只概括了与 stack、queue 有关的内容。

添加元素

append 执行正常 list 的操作,在 list 的末尾加入元素
appendleft 则是在 list 的开头加入元素

queue = collections.deque()
queue.append('a')
queue.append('b')		# deque(['a', 'b'])
queue.appendleft('A')
queue.appendleft('B')	# deque(['B', 'A', 'a', 'b'])

添加可迭代对象

queue.extend(['D', 'E'])		# deque(['B', 'A', 'a', 'b', 'D', 'E'])
queue.extendleft(['c', 'd'])	# deque(['d', 'c', 'B', 'A', 'a', 'b', 'D', 'E'])

"abc" 同样也是 iterable object。如果想将 "abc" 作为整体添加,可以将其作为 ["ABC"] 输入。

弹出元素

queue.pop()						# 'E'
# deque(['d', 'c', 'B', 'A', 'a', 'b', 'D'])
queue.popleft()					# 'd'
# deque(['c', 'B', 'A', 'a', 'b', 'D'])

获取值,不 pop

queue[0]						# 'c'
# deque(['c', 'B', 'A', 'a', 'b', 'D'])
queue[-1]						# ''
# deque(['c', 'B', 'A', 'a', 'b', 'D'])

deque 的大部分的 api 都和 list 非常相似。

232. 用栈实现队列

题目链接 | 解题思路

考验对于栈和队列的掌握,不涉及算法。
重点在如何实现顺序的反转:可以认为一个栈是 FILO,两个栈并用即是 FILO + LIFO = FIFO,即达成了队列的顺序。(非常抽象的概念)

  1. 定义一个输入栈,一个输出栈
  2. 输入栈(以栈的方式)储存输入的元素
  3. 当需要输出(pop)时,将输入栈中的所有元素以相反的顺序输入(pop + push)输出栈中
  4. 此时在输出栈中,元素的顺序就与 queue 中元素一样,pop 即可

FILO + LIFO = FIFO 中的朴素思想:一层栈的储存顺序对于队列来说是一次反转,那么两层栈的储存顺序对于队列来说是两次反转,负负得正即是队列的储存顺序。

以下动图来源于代码随想录。

class MyQueue:

    def __init__(self):
        self.in_stack = []
        self.out_stack = []

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

    def pop(self) -> int:
        if self.out_stack == []:
            for i in range(len(self.in_stack) - 1, -1, -1):
                self.out_stack.append(self.in_stack[i])
            self.in_stack = []
        return self.out_stack.pop(-1)

    def peek(self) -> int:
        last_element = self.pop()
        self.out_stack.append(last_element)
        return last_element

    def empty(self) -> bool:
        return len(self.in_stack) + len(self.out_stack) == 0


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

225. 用队列实现栈

题目链接 | 解题思路

这道题看似和上一题没有区别,但是却没办法直接套用上一题的思路。重点在于队列本身不会扭转数据的顺序,也就是 FIFO + FIFO = FIFO。
实际上,一个队列即可实现顺序的逆转,只需要将 top 元素(除最后一个)弹出后再次加入即可实现逆向。队列在概念上是双向开口的(进出各一端),而栈在概念上是单向开口(进出共用一端)。

class MyStack:

    def __init__(self):
        self.queue = []

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

    def pop(self) -> int:
        if self.queue == []:
            return None
        for i in range(len(self.queue) - 1):
            self.queue.append(self.queue.pop(0))
        return self.queue.pop(0)

    def top(self) -> int:
        top_element = self.pop()
        self.queue.append(top_element)
        return top_element

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


# 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()

deque 解法

以上用 list 模拟队列的方法看上去很符合直觉,但要注意到 list.pop(0) 的复杂度是 O ( n ) O(n) O(n),也就是说 self.pop 的复杂度是 O ( n 2 ) O(n^2) O(n2),实在是太高了。
可以借助 collections.deque 来作为队列的实例。通常来说 deque 的实现是链表,所以删除头元素只需要 O ( 1 ) O(1) O(1),可以大大简化复杂度。

from collections import deque

class MyStack:

    def __init__(self):
        self.queue = deque()

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

    def pop(self) -> int:
        if self.empty():
            return None
        for i in range(len(self.queue) - 1):
            self.queue.append(self.queue.popleft())
        return self.queue.popleft()

    def top(self) -> int:
        top_element = self.pop()
        self.queue.append(top_element)
        return top_element

    def empty(self) -> bool:
        return not len(self.queue)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第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 ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值