- 滑动窗口最大值(单调队列):仅维护当前队列的最大值
from collections import deque - 前k个最大的元素(优先级队列)
import heapq
239. 滑动窗口最大值
思路: 可以考虑使用暴力法进行求解,滑动窗口,自定义单调队列利用O(1)的时间复杂度求解题目的结果。
反思:
- 巧妙的解题思路,仅维护每个序列中最大的数值即可。
- 在每一次弹出时,如果队首是这个元素那么进行弹出,如果不是这个元素就不用进行弹出了。
- 需要自定义一个升序队列。
from collections import deque
# collections中的deque
#list.pop()时间复杂度为O(n),这里需要使用collections.deque()
class MyQueue:
def __init__(self):
self.queue = deque()
def pop(self,value):
if self.queue and value == self.queue[0]:
self.queue.popleft()
def push(self,value):
# 在入队列之前先进行出队列的判定
while self.queue and value > self.queue[-1]:
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 = MyQueue()
result = []
for i in range(k):
que.push(nums[i])
result.append(que.front())
for i in range(k,len(nums)):
que.pop(nums[i-k]) # 如果队首是这个元素那么进行弹出,如果不是这个元素就不用记性弹出了。,首先移除最前的元素
que.push(nums[i])
result.append(que.front())
return result
单调队列的设计原则:
pop():如果窗口移除的值等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
push():如果push的值大于入口元素的数值,那么就将队列出口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
347. 前K个高频元素
难点1: 统计频率(map)
难点2: 对频率进行排序,只需要维护k个有序的集合就可以了,没有必要对所有的顺序进行维护。(大顶堆和小顶堆)
小顶堆: 本质是一个二叉树,根节点是数值最小的元素,在push元素的时候,pop顶的元素,那么剩余的元素就是我们在维护的k个元素。每push一个元素就需要pop一个元素。
# 大顶堆和小顶堆的区分情况
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
#要统计元素出现频率
map_ = {} #nums[i]:对应出现的次数
for i in range(len(nums)):
map_[nums[i]] = map_.get(nums[i], 0) + 1
#对频率排序
#定义一个小顶堆,大小为k
pri_que = [] #小顶堆
#用固定大小为k的小顶堆,扫描所有频率的数值
for key, freq in map_.items():
heapq.heappush(pri_que, (freq, key))
if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
heapq.heappop(pri_que)
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.heappop(pri_que)[1]
return result
大小顶堆的创建:https://blog.youkuaiyun.com/wqylry/article/details/100007328
从二叉树到大小顶堆的调整
也可以直接使用heapq模块进行优先级队列的创建。
python collections库介绍
介绍: 实现特定目标的容器,在python内置的基础数据类型和方法上提供额外的高性能数据类型。
import collections
print(collections.__all__)
['deque', 'defaultdict', 'namedtuple', 'UserDict', 'UserList',
'UserString', 'Counter', 'OrderedDict', 'ChainMap']
常用的两个模块deque和Counter
- deque:类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
from collections import deque
a = deque('abc')
a.append('d') # 在末尾添加元素
a.appendleft('d') # 将元素添加到左端
a.clear() # 移除所有的元素
a.copy() # 创建一份浅拷贝
a.count('a') # 统计a中等于‘a’的个数
a.index('a')
a.insert(a.'x')
a.pop()
a.popleft() # 如果没有元素则引发IndexError
- Counter:字典的子类,提供了可哈希对象的计数功能,可以用来进行统计计数
#上述这样计算有点嘛,下面的方法更简单,直接计算就行
L = ['red', 'blue', 'red', 'green', 'blue', 'blue']
Counter(L)
> Counter({'red': 2, 'blue': 3, 'green': 1}