滑动窗口最大值
算法-滑动窗口最大值
背景
-
算法–滑动窗口最大值
-
博主以代码随想录算法公开课进行学习
题目
-
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
进阶:
你能在线性时间复杂度内解决此题吗?
思路
- 核心逻辑:滑动窗口求最大值的核心是用「单调递减队列」维护窗口内的最大值候选: - 单调递减队列特性:队列中元素从队首到队尾依次递减,队首始终是当前窗口的最大值; - 核心优势:避免暴力遍历窗口(O(nk)),通过队列维护候选值,每个元素仅入队/出队一次,时间复杂度优化至O(n)。
- 具体步骤:
- 自定义单调队列(核心工具):
poll(val):移除窗口左侧滑出的元素——仅当该元素是队首(当前最大值)时,才从队首弹出;add(val):添加窗口右侧新元素——循环剔除队尾所有比当前val小的元素(这些元素不可能成为后续窗口的最大值),再将val加入队尾,保证队列单调递减;peek():获取当前窗口的最大值(队首元素)。
- 滑动窗口执行流程:
- 初始化:将前k个元素加入单调队列,记录第一个窗口的最大值;
- 滑动遍历:从第k个元素开始,依次执行「移除窗口左侧元素→添加窗口右侧元素→记录当前窗口最大值」;
- 最终返回所有窗口的最大值数组。
- 自定义单调队列(核心工具):
代码
1 | class Solution { |
总结
- 核心知识点:
- 单调队列的核心价值:滑动窗口问题中,通过「维护候选值的单调性」避免重复计算,将时间复杂度从暴力法的 O (nk) 优化至 O (n);
- 单调递减队列的设计逻辑:
- 队首:当前窗口的最大值;
- 队中元素:后续窗口可能成为最大值的候选(按递减顺序排列);
- 剔除规则:新元素加入时,剔除所有比它小的队尾元素(这些元素无成为最大值的可能)
- 边界处理:数组长度为 1 时直接返回原数组,避免数组越界。