Leetcode刷题记录22——滑动窗口最大值
题源:https://leetcode.cn/problems/sliding-window-maximum/description/?envType=study-plan-v2&envId=top-100-liked
题目描述:
思路一:
暴力遍历法,通过一个长度为k的滑动窗口遍历nums,将其中最大的数依次记录下来,返回即可,代码如下:
class Solution(object):def maxSlidingWindow(self, nums, k):""":type nums: List[int]:type k: int:rtype: List[int]"""max_num = []for i in range(len(nums) - k + 1):max_num.append(max(nums[i:i+k]))return max_num
不用想肯定超时了,困难题怎么会这么简单呢:
测试一下时间,确实太长了:
思路二:
使用双端队列:
步骤 1: 初始化队列
- 初始时,将前 k 个元素依次加入队列。
- 加入规则:如果队列末尾的元素小于当前元素,则移除末尾元素,直到队列为空或遇到更大的元素。然后将当前元素的索引加入队列。
例子:
初始窗口 [1,3,-1] 的处理:
- 队列为空 → 加入 0(对应 1)。
- 3 > 1 → 移除 0,加入 1(对应 3)。
- -1 < 3 → 直接加入 2(对应 -1)。
此时队列是 [1,2],对应的值为 [3,-1],队头是 3。
步骤 2: 处理后续元素
从第 k 个元素开始,每次窗口滑动一位:
- 移除超出窗口范围的旧元素:
如果队列头部的索引已经不在当前窗口范围内(即 <= i - k),则将其弹出。 - 维护单调队列:
将当前元素 nums[i] 加入队列时,同样遵循规则:移除所有比它小的元素索引,然后将当前索引加入队列。 - 记录当前窗口的最大值:
当窗口形成后(即 i >= k-1),队列头部的索引对应的值就是当前窗口的最大值。
例子:
继续处理 nums[3] = -3(窗口 [3,-1,-3]):
- 窗口起始位置是 i - k + 1 = 1,检查队列头部的 1(对应 3)是否在窗口内(1 >= 1 ,不需要移除)。
- nums[3] = -3 小于队列末尾的 -1(索引 2),直接加入队列。
此时队列是 [1,2,3],对应值为 [3,-1,-3],最大值是 3。
代码实现如下:
class Solution(object):def maxSlidingWindow(self, nums, k):""":type nums: List[int]:type k: int:rtype: List[int]""" result = [] # 存储最终结果q = deque() # 双端队列,存储索引for i in range(len(nums)):# Step 1: 移除超出窗口范围的索引while q and q[0] <= i - k:q.popleft()# Step 2: 维护单调队列(移除比当前元素小的索引)while q and nums[q[-1]] < nums[i]:q.pop()# Step 3: 添加当前索引q.append(i)# Step 4: 当窗口形成后,记录最大值if i >= k - 1:result.append(nums[q[0]])return result
执行用时如下: