📅  最后修改于: 2023-12-03 15:11:08.889000             🧑  作者: Mango
滑动窗口最大值问题,即在一个长度为n的数组中,大小为k的滑动窗口从左向右移动,每次窗口滑动一次,找出当前窗口中的最大值,输出所有窗口中的最大值。本文将介绍解决滑动窗口最大值问题的多种算法。
暴力法的思路是对于每个窗口都遍历一次,找出其中的最大值。时间复杂度是$O(n*k)$,空间复杂度为$O(1)$。
def max_in_window(nums: List[int], k: int) -> List[int]:
if not nums or len(nums) < k:
return []
res = []
for i in range(len(nums) - k + 1):
res.append(max(nums[i:i+k]))
return res
堆方法的思路是维护一个大小为k的最大堆,每次更新堆时,插入新的数之前,需要将窗口之外的数从堆中删除。时间复杂度为$O(nlogk)$,空间复杂度为$O(k)$。
import heapq
def max_in_window(nums: List[int], k: int) -> List[int]:
if not nums or len(nums) < k:
return []
res = []
heap = [-num for num in nums[:k]]
heapq.heapify(heap)
res.append(-heap[0])
for i in range(k, len(nums)):
heapq.heappush(heap, -nums[i])
heapq.heappop(heap)
res.append(-heap[0])
return res
双端队列方法的思路是维护一个双端队列,队列里面存放的是数组下标。每次遍历到一个新的数时,需要将队列中小于当前数的数的下标从队列的右端移除。同时,也要判断队列的左端是否已经窗口之外,如果是,则从队列左端移除。时间复杂度为$O(n)$,空间复杂度为$O(k)$。
def max_in_window(nums: List[int], k: int) -> List[int]:
if not nums or len(nums) < k:
return []
res = []
q = collections.deque()
for i in range(len(nums)):
# 如果队列中存放的数已经不在窗口中,则将其删除
if q and q[0] < i - k + 1:
q.popleft()
# 如果队列中存放的数比当前数小,则将其删除
while q and nums[q[-1]] < nums[i]:
q.pop()
q.append(i)
# 当达到窗口大小时,记录最大值
if i >= k - 1:
res.append(nums[q[0]])
return res
以上就是三种解决滑动窗口最大值问题的方法。其中,暴力法最简单但效率最低,堆和双端队列的时间和空间复杂度都要好于暴力法。在实际应用中,需要根据数据量的大小和算法的实现细节来选择合适的算法。