第五章 栈与队列part02
150. 逆波兰表达式求值
思路:
- 栈与递归之间在某种程度上是可以转换的。
- 逆波兰表达式相当于是二叉树中的后序遍历,可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树。
- 注意负数取整是向零取整方式,,也就是取大。
def div(x, y):
# 使用整数除法的向零取整方式
return int(x / y) if x * y > 0 else -int((abs(x) / abs(y)))
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
op_map={'+':add,'-':sub,'*':mul,'/':div}
stack=[]
for i in tokens:
if i not in op_map:
stack.append(int(i))
else:
op2=stack.pop()#先弹出来的是第二个数
op1=stack.pop()#然后弹出来的是第一个数
stack.append(op_map[i](op1,op2))
return stack.pop()
239. 滑动窗口最大值
- 队列的应用,构造单调队列
思路: - 使用单调队列的经典题目。
- 如果用一个大顶堆(优先级队列)来存放这个窗口里的k个数字,这样就可以知道最大的最大值是多少了, 但是这个窗口是移动的,而大顶堆每次只能弹出最大值,无法移除其他数值,这样就造成大顶堆维护的不是滑动窗口里面的数值了。所以不能用大顶堆。
- 需要一个队列,使得放进去窗口里的元素,随着窗口的移动,队列也一进一出,每次移动之后,队列告诉我们里面的最大值是什么。
- 构造大小为k的单调队列,pop处最大,先进先出,故越前面越大;
- 或者构造大小为k的单调栈,pop处最大,先进后出,故越前面越小
- 每次移动窗口的时候,调用que.pop(滑动窗口中移除元素的数值),que.push(滑动窗口添加元素的数值),然后que.front()就返回我们要的最大值。
- 没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。
- pop和push的操作规则:
- pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
- push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
- queue在没有指定容器的情况下,deque就是默认底层容器。
from collections import deque
class Mydeque:
def __init__(self):
self.queue=deque()#使用deque实现单调队列
#每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
#同时pop之前判断队列当前是否为空。
def pop(self,value):
if self.queue and value==self.queue[0]:
self.queue.popleft()
#如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
#这样就保持了队列里的数值是单调从大到小的了。
def push(self,value):
while self.queue and value>self.queue[-1]:#队列不为空且push元素大于队列最小元素也就是队尾元素时,就一直弹出
self.queue.pop()
self.queue.append(value)
def front(self):
return self.queue[0]#返回队首元素
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
que=Mydeque()
result=[]
for i in range(k):#先将前k的元素放进队列
que.push(nums[i])
result.append(que.front())#result 记录前k的元素的最大值
for i in range(k,len(nums)):
que.pop(nums[i-k])#滑动窗口移除最前面元素
que.push(nums[i])
result.append(que.front())
return result
347.前 K 个高频元素
- 大/小顶堆的应用, 在C++中就是优先级队列
- 本题是 大数据中取前k值 的经典思路
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
from collections import defaultdict
table=defaultdict(int)
for i in nums:
table[i]+=1
# print(sorted(table)[-k:])
# 更改字典,key为出现次数,value为相应的数字的集合
index_dict=defaultdict(list)
for i in table:
index_dict[table[i]].append(i)#键名为出现次数,键值为相应数字
#排序
key=list(index_dict.keys())#出现次数集合
key.sort()#从小到大排序
result=[]
cnt=0
#获取前K项
while key and cnt!=k:
result+=index_dict[key[-1]]#最大的次数(可能有多个数值)
cnt+=len(index_dict[key[-1]])#计算相同次数的数出现了几次
key.pop()
return result