目录
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