题目描述
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
问题分析
需要在一个大小为 k 的滑动窗口内找到当前窗口内的最大值。滑动窗口从数组的最左侧开始,每次向右移动一位。最简单的方式是对于每个窗口都遍历其内部元素找出最大值,但这种方法的时间复杂度较高
优化思路
可以利用双端队列(Deque)来优化这个过程,使得在每次移动滑动窗口时都能在 O(1) 的时间复杂度内得到当前窗口的最大值。
具体步骤
1、我们维护一个双端队列 deque,其中存储数组元素的索引,并且保证队列中存储的索引对应的数组值是单调递减的。这样,队列的第一个元素总是当前窗口的最大值的索引。
2、在滑动窗口向右移动一位时,首先检查队列的头部元素是否已经不在当前窗口内(即 deque[0] 小于窗口的左边界),如果是,则将其从队列中移除。
3、然后,将当前遍历到的元素的索引加入队列尾部。在加入之前,移除队列尾部那些比当前元素小的所有元素,因为它们不可能成为后续窗口中的最大值。
4、当遍历到的索引大于或等于 k-1 时(即窗口已经形成),将当前窗口的最大值(即 deque[0] 对应的元素)加入结果集中。
```python
from collections import deque
def maxSlidingWindow(nums, k):
if not nums:
return []
deque_window = deque()
max_values = []
for i in range(len(nums)):
# 移除窗口外的元素
if deque_window and deque_window[0] < i - k + 1:
deque_window.popleft()
# 移除所有小于当前元素的元素
while deque_window and nums[deque_window[-1]] < nums[i]:
deque_window.pop()
# 添加当前元素的索引
deque_window.append(i)
# 当前窗口形成时,将最大值加入结果集
if i >= k - 1:
max_values.append(nums[deque_window[0]])
return max_values
或者自定义单调栈
from collections import 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()
res = []
# 先将前k的元素导入单调递减队列
for i in range(k):
que.push(nums[i])
res.append(que.front())
# 移动窗口
for i in range(k, len(nums)):
que.pop(nums[i - k])
que.push(nums[i])
res.append(que.front())
return res