五、栈与队列(1)

理论基础

在Python中,与栈(stack)[]和队列(queue)= deque()相关的问题可以通过一些内置的数据结构和模块来解答。

1. Python中的stack是容器么?

是的,栈(stack)是一种常用的数据容器。在Python中,栈通常使用列表(list)来实现,虽然Python没有专门的栈数据结构,但列表提供的append()和pop()方法可以非常方便地实现栈的功能。

2. 我们使用的stack是属于哪个版本的STL?

Python中没有C++标准模板库(STL)的概念,因为Python的标准库已经包含了许多内置的容器类型和模块来实现类似的功能。栈在Python中可以使用内置的list实现,也可以使用collections模块中的deque来实现。

3. 我们使用的stack是如何实现的?

在Python中,可以通过list或collections.deque来实现栈:

  • 使用list实现栈:

    stack = []
    stack.append(1)  # 压栈
    stack.append(2)  # 压栈
    item = stack.pop()  # 出栈,item = 2
    
  • 使用collections.deque实现栈:

    from collections import deque
    
    stack = deque()
    stack.append(1)  # 压栈
    stack.append(2)  # 压栈
    item = stack.pop()  # 出栈,item = 2
    

deque(双端队列)在性能上比list更优,因为它是为高效的头部和尾部操作而设计的。

4. stack提供迭代器来遍历stack空间么?

是的,Python中的list和deque都提供迭代器来遍历其元素。例如:

  • 使用list迭代:

    stack = [1, 2, 3, 4]
    for item in stack:
        print(item)
    
  • 使用deque迭代:

    from collections import deque
    
    stack = deque([1, 2, 3, 4])
    for item in stack:
        print(item)
    

这两种方法都可以方便地遍历栈中的所有元素。

在Python中,collections.deque(双端队列)是一个可以高效地在两端添加和删除元素的容器。要实现先进先出(FIFO)队列,可以使用deque的以下方法:

  • append() 在队列尾部添加元素
  • pop()尾部弹出并返回元素
  • popleft() 从队列头部删除并返回元素
  • appendleft()队列头部添加元素

deque 的其他方法

collections.deque 还提供了其他有用的方法,如:

  • extend(iterable):在队列尾部添加多个元素
  • extendleft(iterable):在队列头部添加多个元素(注意,这些元素会以倒序添加到队列中)
  • remove(value):移除队列中第一次出现的value
  • rotate(n):旋转队列,正数n将元素右移,负数n将元素左移

这些方法使得deque非常灵活,可以用于多种不同的数据处理需求。

代码示例

from collections import deque

# 创建一个deque并添加一些元素
queue = deque(['a', 'b', 'c'])

# 在尾部添加元素
queue.append('d')
print(queue)  # 输出: deque(['a', 'b', 'c', 'd'])

# 在头部添加元素
queue.appendleft('z')
print(queue)  # 输出: deque(['z', 'a', 'b', 'c', 'd'])

# 从尾部删除元素
print(queue.pop())  # 输出: d
print(queue)        # 输出: deque(['z', 'a', 'b', 'c'])

# 从头部删除元素
print(queue.popleft())  # 输出: z
print(queue)            # 输出: deque(['a', 'b', 'c'])

# 扩展队列
queue.extend(['e', 'f'])
print(queue)  # 输出: deque(['a', 'b', 'c', 'e', 'f'])

# 头部扩展队列
queue.extendleft(['y', 'x']) # 倒序插入
print(queue)  # 输出: deque(['x', 'y', 'a', 'b', 'c', 'e', 'f'])

# 旋转队列
queue.rotate(2)
print(queue)  # 输出: deque(['e', 'f', 'x', 'y', 'a', 'b', 'c'])

queue.rotate(-3)
print(queue)  # 输出: deque(['y', 'a', 'b', 'c', 'e', 'f', 'x'])

232.用栈实现队列

借助另一个出栈,栈实现队列的出队操作效率低下:栈底元素(对应队首元素)无法直接删除,需要将上方所有元素出栈。
可以设计栈 A 用于加入队尾操作,栈 B 用于将元素倒序,从而实现删除队首元素。
法一,老老实实每次倒出来再倒回去.

class MyQueue:

    def __init__(self):
        self.a, self.b = [], []


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


    def pop(self) -> int:
        # a not null
        while self.a:
            self.b.append(self.a.pop())
        ans = self.b.pop()
        while self.b:
            self.a.append(self.b.pop())
        return ans


    def peek(self) -> int:
        # a not null
        while self.a:
            self.b.append(self.a.pop())
        ans = self.b[-1]
        while self.b:
            self.a.append(self.b.pop())
        return ans


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


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

法二,始终保持B是倒序A是正序B是倒序的,反正要peek完B里面的才轮到后面新A加进来的。而且也没说要返回一个完整的队列。
如果B不为空,返回B的最后一个,也就是原来最先进A的;如果B为空,这时有两个情况,A也为空,返回-1,A不为空,说明(可能一开局或者已经pop完了),就把A倒序倒到B中。`刚开始不理解,万一后面A又push新的了怎么办?新的还在A里面,如果要pop或者peek,反正先把B 里面的搞完,如果还要继续peek,此时B空了,又回到A不空,B空的条件,把A倒进B。

类内部函数互相调用也得self,不可以直接从B里面pop,因为不知道B是否空return self.B.pop()虽然能直接返回,但是错错错
代码复用,减少错的可能

class MyQueue:

    def __init__(self):
        self.A, self.B = [], []


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


    def pop(self) -> int:
        # peek返回的元素肯定是从B里面来的
        # 删除也在B里面删 直接pop即可
        # 要返回删除的值
        val = self.peek()  # 类内部调用
        self.B.pop() 
        return val  
        # 不可以直接从B里面pop,因为不知道B是否空
        # return self.B.pop()


    def peek(self) -> int:
        if self.B:
            return self.B[-1]
        elif not self.A:
            return -1
        else:
            while self.A:
                self.B.append(self.A.pop())
            return self.B[-1]



    def empty(self) -> bool:
        return not self.A and not self.B  # A B都是空(false)才true,



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

时间复杂度: push和empty为O(1), pop和peek为O(n)
空间复杂度: O(n)

225. 用队列实现栈

只用一个队列实现,此时队列只能popleft(),拿出来再放到末尾,用len()控制循环

class MyStack:

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


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


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


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


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



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

20. 有效的括号

利用先进后出(更早期待,更晚遇到)
先想有哪些错误类型1 左括号多了 2 右括号多了 3 括号不匹配(即与预判的不相等)

class Solution:
    def isValid(self, s: str) -> bool:
        stack = []

        # 不考虑空
        for c in s:
            if c == '(':
                stack.append(')')
            elif c == '{':
                stack.append('}')
            elif c == '[':
                stack.append(']')
            elif stack and c == stack.pop() :
                continue
            else:
                return False  # 匹配不上的,或者右边多,stack已空
            
        return not stack

            

时间复杂度: O(n)
空间复杂度: O(n)

1047. 删除字符串中的所有相邻重复项

这种重复or对称的都可以用更早预判放入栈,更晚遇到相比较的栈的数据结构处理

class Solution:
    def removeDuplicates(self, s: str) -> str:
        stack = []
        for c in s:
            if stack:
                temp = stack.pop()
                if c == temp:
                    s = s.replace(c+c, "")
                else:
                    stack.append(temp)
                    stack.append(c)
            else:
                stack.append(c)
            
        return s


想知道栈的最后一个直接[-1]即可
类似消消乐,也可以把所有都放入栈,遇到相同的消除,最后"".join(res)字符串拼接一下

  • 23
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值