滑动窗口最大值问题是一种常见的算法问题,通常涉及在一个给定大小的窗口中找到每个位置的最大值。这个问题可以使用不同的方法来解决,最常用的高效方法是利用双端队列(deque)来实现滑动窗口的最大值计算。
问题描述
给定一个数组和一个窗口大小k
,要求返回一个数组,其中每个元素是原数组中对应窗口的最大值。
例如,给定数组 [1, 3, -1, -3, 5, 3, 6, 7]
和窗口大小 3
,返回 [3, 3, 5, 5, 6, 7]
。
方法 1: 使用双端队列(Deque)
双端队列是一种可以在两端高效插入和删除元素的数据结构。我们可以使用双端队列来保持窗口内的最大值。
代码实现
from collections import deque
def max_sliding_window(nums, k):
if not nums:
return []
# 双端队列,存储索引
deq = deque()
result = []
for i in range(len(nums)):
# 移除不在当前窗口范围的元素
if deq and deq[0] == i - k:
deq.popleft()
# 移除队列中小于当前元素的元素
while deq and nums[deq[-1]] < nums[i]:
deq.pop()
deq.append(i)
# 从第 k-1 个位置开始,记录最大值
if i >= k - 1:
result.append(nums[deq[0]])
return result
# 使用示例
nums = [1, 3, -1, -3, 5, 3, 6, 7]
k = 3
print(max_sliding_window(nums, k)) # 输出: [3, 3, 5, 5, 6, 7]
解释
-
初始化:使用一个双端队列
deq
来存储当前窗口的索引。result
用于存储每个窗口的最大值。 -
处理窗口范围:
- 当窗口向前滑动时,移除队列中不在当前窗口范围内的元素(索引超出
i - k
)。
- 当窗口向前滑动时,移除队列中不在当前窗口范围内的元素(索引超出
-
维护队列:
- 移除队列中所有小于当前元素的索引,因为这些元素不可能是窗口内的最大值。
- 将当前元素的索引添加到队列中。
-
记录最大值:
- 从索引
i = k - 1
开始,每次滑动窗口都记录队列中第一个元素对应的最大值(即窗口的最大值)。
- 从索引
时间复杂度
- 时间复杂度:
O(n)
,每个元素被加入和移除队列至多一次。 - 空间复杂度:
O(k)
,队列中最多保存窗口大小的元素索引。
这个方法非常高效,适用于大多数滑动窗口最大值的计算问题,并且能够处理大规模数据集。