滑动窗口最大值
题目连接 leetcode 239.
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
一个简单的思路就是对每一次的窗口进行一次max 运算,然后窗口向右一个个滑动。但是每一次max运算都是
O
(
k
)
O(k)
O(k),那么这样的算法时间复杂度太高了。而且窗口滑动前后,两次max运算中其实是有重复运算的,也就是造成了冗余运算。那么我们该如何保留最大值信息,同时减少时间复杂度呢?
一种想法是运用单调队列。单调队列,顾名思义是元素从大到小或者从小到大排序的队列 (但是队尾可以弹出)。 单调队列的添加元素value,需要把队尾所有小于value的值全部弹出后再添加。
如果把一个数组依次添加到单调队列,则最后的单调队列会是一个由最大值为队头,下降(上升)速度最慢的子数组。
应用到本题中,窗口向右移动一位,队列更新一次,此时的队列的队头即为最大值。窗口左端右移一位,如果删除的这个元素是最大值(等于队头),则队头需弹出;如果不是,说明下一个的最大值仍然相等,且队列不变,因此不需要对队列进行操作。窗口右端右移,将元素添加到单调队列中。
python 代码
from collections import deque
class MyQueue:
def __init__(self):
self.que = deque()
def pop(self,value):
if self.que[0] == value:
self.que.popleft()
def push(self,value):
while self.que and self.que[-1] < value:
self.que.pop()
self.que.append(value)
def front(self):
return self.que[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
前k个高频元素
题目连接 leetcode 347.
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案
思路于 代码随想录
- 用字典统计元素及其对应的频数
- 用小顶堆维护大小为k的数组
- 倒序输出小顶堆
Python 代码
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
count = {}
for i in nums:
count[i] = count.get(i,0) + 1
pri_que = []
for (keys,values) in count.items():
heapq.heappush(pri_que,(values,keys))
if len(pri_que) > k:
heapq.heappop(pri_que)
result = [0] * k
for i in range(k-1,-1,-1):
result[i] = heapq.heappop(pri_que)[1]
return result