栈与队列——239.滑动窗口最大值,347.前 K 个高频元素
文档链接:代码随想录
做题感悟:
- 滑动窗口最大值:利用单调队列实现对滑动窗口最大值的判断,通过遍历滑动窗口,更新队列的同时,得到每个滑动窗口最大值
- 前k个高频元素;哈希表+小顶堆。其中python利用heapq模块实现小顶堆结构。小顶堆在push和pop过程中仍然会维护小顶堆的结构
- 顺便再回忆下哈希表的访问方式。
题目一:239.滑动窗口最大值——40min
- 为了实现滑动窗口最大值
- 首先需要实现对滑动窗口的左侧pop,右侧push,同时返回最大值
- 为了保证寻找最大值的复杂度尽可能的小,可以构建一个单调队列,再更新队列的同时保证队列的第一个元素始终是最大值,进而降低复杂度。
- 在pop队列的最大值时,先判断是否是滑动窗口要pop的元素
- 在push元素的时候,先判断前面的元素是否比当前元素大,如果大于就pop,进而保证了队列的单调性。
- 由于队列是滑动窗口的子集,同时队列单调,因此就能保证队列的第一个元素是滑动窗口的最大值。
class Mydeque:
# 定义一个单调队列的基本操作,保证队列内的元素永远是第一个最大,单调递减
def __init__(self):
self.deque=deque() # 初始化队列
def pop(self,value: int) -> None:
if self.deque and self.deque[0] == value:
self.deque.popleft()
return
# 如果是滑动窗口pop的元素正好是队列末尾的元素,则pop该元素。
# 保证队列内元素是滑动窗口元素的子集,并且起始元素是最大值。
# 如果不相等,实际上也会被push操作给淘汰了。
def push(self,value: int) -> None:
while self.deque and value > self.deque[-1]:
self.deque.pop() # 将小于value的值从右边pop
self.deque.append(value)
return
def getmax(self):
return self.deque[0]
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
# 定义三个函数。
# pop,如果滑动窗口起始下标的前一个是当前最大值,则将最大值pop
# push,如果滑动窗口下一个要放进去的数值比前面的都大,则将前面的元素pop。
# getmax,获得当前队列的最大值。
# python的队列为双向队列,利用popleft从down推出,利用pop实现将元素从top推出。
que = Mydeque()
ans=[]
for i in range(k):
que.push(nums[i])
ans.append(que.getmax())
for i in range(k,len(nums)):
que.pop(nums[i-k])
que.push(nums[i])
ans.append(que.getmax())
return ans
题目二:347.前 K 个高频元素——80min
- python的heapq库使用。
- 先用哈希表求频次复杂度为log(n)
- 在用小顶堆,保证堆内元素永远是前k个,多出来的元素则被pop出去。
heapq.heappop(haep_)
:表示pop最小元素,同时维持小顶堆结构。如果pop后的元素为空,则会出现错误。可以用heap_[0]进行访问。
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# 利用堆结构实现堆排序。
# 先用哈希表求频次
# 利用长度为k的堆,寻找前K个高频元素
# 利用小顶堆,在超过k个元素的情况下,将根节点pop。保证小顶堆内的元素始终是最大的前k个元素
map_={}
for i in range(len(nums)):
map_[nums[i]] = map_.get(nums[i],0)+1
# 记住python访问字典的方式,以及记录频次的方式
heap_= []
for key,freq in map_.items():
heapq.heappush(heap_,(freq,key)) # 小顶堆以第一个数值为标准
if len(heap_)>k:
heapq.heappop(heap_)
result=[0]*k
for i in range(len(result)):
result[i] = heap_[i][1]
return result