队列/栈/堆试题(Python实现)

目录

1. 两个栈实现队列

2. 包含min函数的栈(双栈实现最小栈)

3. 有效括号序列(栈)

4. 表达式求值(栈)

5. 栈的压入、弹出序列

6. 最小的K个数(用小根堆)

7. TopK 寻找第K大(用大根堆)

8. 数据流中的中位数(大根堆+小根堆实现)

9. 滑动窗口的最大值


1. 两个栈实现队列

  • push直接入1栈
  • pop先把1栈的全移到2栈,pop完再全移回去
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    # push直接入1栈,pop把1栈的全移到2栈 pop后全移回去
    def push(self, node):
        self.stack1.append(node)
    def pop(self):
        # 先把第一个栈的内容移入
        while self.stack1:
            self.stack2.append(self.stack1.pop())
        res = self.stack2.pop()
        # 在把第二栈内容全移走
        while self.stack2:
            self.stack1.append(self.stack2.pop())
        return res

2. 包含min函数的栈(双栈实现最小栈

一个正常栈,一个最小栈(始终添加当前最小值)

class Solution:
    def __init__(self):
        self.stack = []
        self.stack_min = []
    def push(self, node):
        self.stack.append(node)
        # 最小栈始终添加最小值
        if self.stack_min is None:
            self.stack_min.append(node)
        elif node < self.stack_min[-1]:
            self.stack_min.append(node)
        else:
            self.stack_min.append(self.stack_min[-1])
    def pop(self):
        self.stack.pop()
        self.stack_min.pop()
    def top(self):
        return self.stack[-1]
    def min(self):
        return self.stack_min[-1]

3. 有效括号序列(栈)

class Solution:
    def isValid(self , s: str) -> bool:
        stack = []
        for i in range(len(s)):
            if s[i] == '(':
                stack.append(')')
            elif s[i] == '{':
                stack.append('}')
            elif s[i] == '[':
                stack.append(']')
            # 出现右括号,而栈为空
            elif len(stack) == 0:
                return False
            elif stack.pop() != s[i]:
                return False
        return False if stack else True

4. 表达式求值(栈)

class Solution:
    def solve(self , s: str) -> int:
        s = s.strip()
        stack = []
        res = 0
        num = 0
        sign = '+'
        i = 0
        while i < len(s):
            if s[i] == ' ':
                continue
            if s[i] == '(':
                end = i + 1
                nums = 1
                # 解决子括号问题
                while nums > 0:
                    if s[end] == '(':
                        nums += 1
                    if s[end] == ')':
                        nums -= 1
                    end += 1
                # 递归括号中的子问题
                num = self.solve(s[i+1:end-1])
                i = end - 1
                continue
            # 数字
            if '0' <= s[i] <= '9':
                num = num*10 + int(s[i])
            # 运算符
            if not '0' <= s[i] <= '9' or i == len(s)-1:
                if sign == '+':
                    stack.append(num)
                elif sign == '-':
                    stack.append(-1*num)
                elif sign == '*':
                    stack.append(stack.pop() * num)
                num = 0
                sign = s[i]
            i += 1
        # 栈中元素相加即可
        while stack:
            res += stack.pop()
        return res

5. 栈的压入、弹出序列

class Solution:
    def IsPopOrder(self , pushV: List[int], popV: List[int]) -> bool:
        n = len(pushV)
        # 模拟栈
        stack = []
        # 弹出序列下标
        j = 0
        for i in range(n):
            stack.append(pushV[i])
            while stack != [] and stack[-1] == popV[j]:
                stack.pop()
                j += 1
        return stack == []

6. 最小的K个数(用小根堆)

Ⅰ.全入小根堆        Ⅱ.pop出的k个元素均为最小值

import heapq
class Solution:
    def GetLeastNumbers_Solution(self , input: List[int], k: int) -> List[int]:
        res = []
        # 小根堆
        pq = []
        # 全部放入小根堆
        for i in range(len(input)):
            heapq.heappush(pq, input[i])
        # pop k个
        for i in range(k):
            res.append(heapq.heappop(pq))
        return res

大根堆法:构建大小为k的大根堆,每次比较堆顶元素,小于堆顶则入堆。

import heapq
# Python中默认为小根堆,因此存入时取负(当作大根堆使用)
class Solution:
    def GetLeastNumbers_Solution(self , input: List[int], k: int) -> List[int]:
        res = []
        if k <= 0 or k > len(input): return res
        pq = []
        # 构建大小为k的大根堆
        for i in range(k):
            heapq.heappush(pq, -1 * input[i])
        for i in range(k, len(input)):
            # 小于堆顶元素的入堆
            if input[i] < -1 * pq[0]:
                heapq.heapreplace(pq, -1 * input[i])
        # 取出结果
        for _ in range(k):
            res.append(-1 * heapq.heappop(pq))
        return res[::-1]

7. TopK 寻找第K大(用大根堆)

Ⅰ.全入大根堆        Ⅱ.循环pop出k-1次        Ⅲ.return第k个poll的元素

import heapq
class Solution:
    def findKth(self , a: List[int], n: int, K: int) -> int:
        pq = []
        # 全部存入大根堆
        for i in range(n):
            heapq.heappush(pq, -1 * a[i])
        # pop出k-1次
        for i in range(K-1):
            heapq.heappop(pq)
        # 返回第k次pop的值
        return -1*heapq.heappop(pq)

小根堆法:

import heapq
class Solution:
    def findKth(self , a: List[int], n: int, K: int) -> int:
        # 构建大小为k的小根堆
        pq = []
        for i in range(K):
            heapq.heappush(pq, a[i])
        for i in range(K, n):
            # 大元素入堆
            if pq[0] < a[i]:
                heapq.heapreplace(pq, a[i])
        # 当前k个为k个最大的元素,堆顶为k个中最小的元素(第K大)
        return heapq.heappop(pq)

8. 数据流中的中位数(大根堆+小根堆实现)

import heapq
class Solution:
    def __init__(self):
        # 小根堆
        self.pq_min = []
        # 大根堆
        self.pq_max = []
    def Insert(self, num):
        # 先加入大根堆
        heapq.heappush(self.pq_max, -1*num)
        # 取出大根堆中的最大值,存入小根堆
        heapq.heappush(self.pq_min, -1 * heapq.heappop(self.pq_max))
        # 平衡两堆数量(如果大根堆少了,再取回来)
        if len(self.pq_max) < len(self.pq_min):
            heapq.heappush(self.pq_max, -1 * heapq.heappop(self.pq_min))

    def GetMedian(self):
        # 奇数个
        if len(self.pq_max) > len(self.pq_min):
            return self.pq_max[0] * -1
        # 偶数个
        else:
            return (self.pq_min[0] + (-1 * self.pq_max[0]))/2

9. 滑动窗口的最大值

class Solution:
    def maxInWindows(self , num: List[int], size: int) -> List[int]:
        res = []
        if size <= 0 or size > len(num): return res
        for i in range(len(num) - size + 1):
            # 寻找每个窗口的最大值
            maxx = 0
            for j in range(i, i + size):
                maxx = max(maxx, num[j])
            res.append(maxx)
        return res

双向队列

from collections import deque
class Solution:
    def maxInWindows(self , num: List[int], size: int) -> List[int]:
        res = []
        if size <= 0 or size > len(num): return res
        # 双向队列
        dq = deque()
        # 遍历第一个窗口
        for i in range(size):
            # 去掉小值
            while len(dq) != 0 and num[dq[-1]] < num[i]:
                dq.pop()
            dq.append(i)
        # 遍历后续数组
        for i in range(size, len(num)):
            res.append(num[dq[0]])
            # 移除上一个窗口中的值
            while len(dq) != 0 and dq[0] < (i - size + 1):
                dq.popleft()
            # 去掉小值
            while len(dq) != 0 and num[dq[-1]] < num[i]:
                dq.pop()
            dq.append(i)
        res.append(num[dq[0]])
        return res

猜你喜欢

转载自blog.csdn.net/qq_52057693/article/details/128848036