【Hot100|13-LeetCode 56. 合并区间】

LeetCode 239. 滑动窗口最大值 - 单调队列解法详解
一、问题理解
问题描述
给定一个整数数组 nums 和一个整数 k,滑动窗口从数组的最左侧移动到最右侧,每次只向右移动一位。请找出所有滑动窗口中的最大值,并返回这些最大值组成的数组。

示例
text

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
窗口位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
二、核心思路:单调队列维护潜在最大值
暴力解法的局限性
对于每个窗口都重新遍历 k 个元素找最大值,时间复杂度为 O(nk),效率极低。

单调队列优化思路
单调队列定义:使用双端队列(Deque)维护一个单调递减的队列,存储元素的索引。

队列特性:

队列中的索引对应的元素值从队首到队尾单调递减。

队首元素总是当前窗口的最大值。

维护操作:

入队:新元素入队时,从队尾开始移除所有小于等于它的元素,然后入队。

出队:检查队首元素是否还在当前窗口内,如果不在则移除。

获取最大值:窗口完全形成后,队首元素即为当前窗口最大值。

三、代码逐行解析
Java 解法
java

import java.util.ArrayDeque;
import java.util.Deque;

class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
// 1. 结果数组:滑动窗口的个数为 n - k + 1
int[] ans = new int[n - k + 1];
// 2. 双端队列:存储元素索引,维护队列内元素值单调递减
Deque<Integer> q = new ArrayDeque<>();

// 3. 遍历数组的每个元素
for (int i = 0; i < n; i++) {
// 3.1 新元素从队尾入队,维护队列单调性
// 从队尾开始,移除所有小于等于当前元素的索引
// 因为这些元素不可能成为后续窗口的最大值
while (!q.isEmpty() && nums[q.getLast()] <= nums[i]) {
q.removeLast();
}
// 将当前元素索引加入队尾
q.addLast(i);

// 3.2 移除窗口外的元素
// 计算当前窗口的左边界
int left = i - k + 1;
// 如果队首索引小于左边界,说明队首元素不在当前窗口内
if (q.getFirst() < left) {
q.removeFirst();
}

// 3.3 当窗口完全形成时,记录当前窗口最大值
// 当 left >= 0 时,窗口已包含 k 个元素
if (left >= 0) {
ans[left] = nums[q.getFirst()];
}
}

// 4. 返回结果
return ans;
}
}
Python 解法
python

from collections import deque
from typing import List

class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
# 1. 边界处理
if n == 0 or k == 0:
return []

# 2. 初始化结果数组和双端队列
ans = [0] * (n - k + 1)
q = deque()

# 3. 遍历数组
for i in range(n):
# 3.1 维护队列单调性
# 从队尾开始,移除所有小于等于当前元素的索引
while q and nums[q[-1]] <= nums[i]:
q.pop()
# 将当前索引加入队尾
q.append(i)

# 3.2 移除窗口外的元素
# 计算当前窗口的左边界
left = i - k + 1
# 如果队首索引小于左边界,说明不在当前窗口内
if q[0] < left:
q.popleft()

# 3.3 记录结果(当窗口完全形成时)
if left >= 0:
ans[left] = nums[q[0]]

# 4. 返回结果
return ans
四、Java 与 Python 语法对比
1. 队列操作
操作 Java Python
创建双端队列 Deque<Integer> q = new ArrayDeque<>(); q = deque()
获取队尾元素 q.getLast() q[-1]
移除队尾元素 q.removeLast() q.pop()
获取队首元素 q.getFirst() q[0]
移除队首元素 q.removeFirst() q.popleft()
添加元素到队尾 q.addLast(i) q.append(i)
2. 数组/列表操作
操作 Java Python
创建数组 int[] ans = new int[n - k + 1]; ans = [0] * (n - k + 1)
获取数组长度 nums.length len(nums)
获取数组元素 nums[i] nums[i]
3. 循环与控制流
操作 Java Python
for 循环 for (int i = 0; i < n; i++) for i in range(n):
while 循环 while (!q.isEmpty() && ...) while q and ...:
五、实例演示
以测试用例 nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3 为例,演示过程:

步骤 i nums[i] 队列操作(维护单调性后) 队列(索引,值) left 队首在窗口内? ans[left]
1 0 1 空队列,直接加入0 [0(1)] -2 不判断 -
2 1 3 1(3) > 0(1),移除0,加入1 [1(3)] -1 不判断 -
3 2 -1 队尾1(3) > -1,直接加入2 [1(3), 2(-1)] 0 是 (1>=0) ans[0]=3
4 3 -3 队尾2(-1) > -3,直接加入3 [1(3), 2(-1), 3(-3)] 1 是 (1>=1) ans[1]=3
5 4 5 依次移除3(-3), 2(-1), 1(3),加入4 [4(5)] 2 是 (4>=2) ans[2]=5
6 5 3 队尾4(5) > 3,直接加入5 [4(5), 5(3)] 3 是 (4>=3) ans[3]=5
7 6 6 移除5(3), 4(5),加入6 [6(6)] 4 是 (6>=4) ans[4]=6
8 7 7 移除6(6),加入7 [7(7)] 5 是 (7>=5) ans[5]=7
最终结果:ans = [3, 3, 5, 5, 6, 7]

六、关键细节解析
1. 为什么队列存储索引而不是值?
索引可以判断元素是否在窗口内:通过比较索引和窗口左边界,可以知道元素是否已经滑出窗口。

值无法判断位置:如果只存储值,无法知道该值对应的元素是否还在当前窗口内。

2. 为什么入队时要移除小于等于当前元素的队尾元素?
假设队列尾部有元素 x,当前元素为 y,且 x <= y:

y 比 x 更大(或相等)且更靠右(索引更大)。

在后续窗口中,y 会比 x 更晚离开窗口。

因此,x 永远不可能成为后续窗口的最大值,可以安全移除。

3. 窗口何时完全形成?
当 i >= k - 1 时,left = i - k + 1 >= 0,此时窗口包含 k 个元素,可以记录最大值。

4. 为什么队首一定是当前窗口的最大值?
队列维护了从队首到队尾的单调递减性。

队首元素是当前窗口中最早加入队列且未被移除的元素。

通过入队时的筛选,队首元素一定大于队列中其他元素,且在当前窗口内。

七、复杂度分析
时间复杂度:O(n)
每个元素最多入队一次、出队一次。

每个元素的操作次数是常数级别。

总操作次数为 O(n)。

空间复杂度:O(k)
队列中最多同时存储 k 个元素(当数组单调递减时)。

结果数组 O(n-k+1) 不计入空间复杂度(属于输出要求)。

八、优化技巧与变体
1. 处理边界情况
python

def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums or k <= 0:
return []
n = len(nums)
if k == 1:
return nums
if k >= n:
return [max(nums)]

# 后续逻辑...
2. 使用数组模拟双端队列(优化空间)
python

def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
if n == 0 or k == 0:
return []

# 使用列表模拟双端队列
q = [0] * n # 预分配空间
front, rear = 0, -1 # 队列的头部和尾部指针
ans = [0] * (n - k + 1)

for i in range(n):
# 维护队列单调性
while front <= rear and nums[q[rear]] <= nums[i]:
rear -= 1
rear += 1
q[rear] = i

# 移除窗口外的元素
if q[front] < i - k + 1:
front += 1

# 记录结果
if i >= k - 1:
ans[i - k + 1] = nums[q[front]]

return ans
3. 使用优先队列(堆)的解法
python

import heapq
from typing import List

class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums or k == 0:
return []

n = len(nums)
# 使用最大堆,存储(-值,索引)对,因为Python的heapq是最小堆
heap = []
result = []

for i in range(n):
# 将当前元素加入堆中
heapq.heappush(heap, (-nums[i], i))

# 当窗口完全形成时
if i >= k - 1:
# 移除堆顶不在窗口内的元素
while heap and heap[0][1] <= i - k:
heapq.heappop(heap)
# 堆顶元素就是当前窗口的最大值
result.append(-heap[0][0])

return result
复杂度分析:

时间复杂度:O(n log n),每个元素入堆出堆需要 O(log n)

空间复杂度:O(n)

缺点:比单调队列解法慢,但逻辑更简单。

九、常用函数积累
Java 常用函数
java

// 双端队列操作
Deque<Integer> deque = new ArrayDeque<>();
deque.addLast(element); // 添加到队尾
deque.removeLast(); // 移除队尾
deque.getLast(); // 获取队尾
deque.addFirst(element); // 添加到队首
deque.removeFirst(); // 移除队首
deque.getFirst(); // 获取队首
deque.isEmpty(); // 判断队列是否为空
deque.size(); // 获取队列大小

// 数组操作
int[] arr = new int[n];
int length = arr.length; // 数组长度
Arrays.fill(arr, value); // 填充数组
Python 常用函数
python

from collections import deque

# 双端队列操作
q = deque()
q.append(element) # 添加到队尾
q.pop() # 移除队尾
q[-1] # 获取队尾
q.appendleft(element) # 添加到队首
q.popleft() # 移除队首
q[0] # 获取队首
len(q) # 获取队列大小
bool(q) # 判断队列是否非空

# 列表操作
arr = [0] * n
len(arr) # 列表长度
max(arr) # 获取最大值
min(arr) # 获取最小值
十、总结
核心要点
单调队列是关键:维护一个单调递减的队列,队首元素始终是当前窗口的最大值。

索引存储很重要:存储索引而非值,可以方便地判断元素是否在窗口内。

时间复杂度优化:从暴力解法的 O(nk) 优化到 O(n)。

面试常见问题
为什么使用单调队列而不是优先队列?

单调队列的均摊时间复杂度是 O(1),而优先队列是 O(log n)。

单调队列更适合滑动窗口问题,因为元素是按顺序加入和移除的。

如何处理数组中有重复元素的情况?

算法天然支持重复元素,因为入队时移除的是小于等于当前元素的元素。

如果有多个相同的最大值,队列中会保留最右侧的那个(索引最大的)。

如果 k 很大,接近 n 怎么办?

算法仍然有效,队列大小最多为 k,空间复杂度 O(k)。

当 k >= n 时,只需要返回整个数组的最大值。

最坏情况下的时间复杂度?

每个元素最多入队一次、出队一次,所以是 O(n)。

如果数组是单调递增的,队列会怎样?

队列中最多只会有一个元素,因为每个新元素都会移除之前的所有元素。

扩展思考
类似问题:

滑动窗口最小值(只需将单调递减改为单调递增)

滑动窗口的中位数(需要更复杂的数据结构)

滑动窗口的平均值(更简单,只需维护窗口和)

变体问题:

限制大小的队列最大值(队列有最大容量,需要支持push和pop)

二维滑动窗口最大值(更复杂,需要结合单调队列和动态规划)

实际应用:

股票价格分析(寻找一段时间内的最高价)

网络流量监控(统计固定时间窗口内的最大流量)

图像处理(滑动窗口滤波器)

掌握单调队列的解法,不仅能够解决滑动窗口最大值问题,还能够解决一系列类似的区间最值问题,是面试中非常重要的算法技巧。
————————————————
版权声明:本文为CSDN博主「好学且牛逼的马」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/King_model/article/details/154684394

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1221142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鼠标手势(Cursor)演示

auto / 自动 default / 默认 none / 隐藏 pointer / 链接手 text / 文本选择 vertical-text / 竖排文本 wait / 等待 progress / 加载中 help / 帮助 not-allowed / 禁止 no-drop / 不可放置 crosshair / 十字线 cell …

CSS 学习笔记 (1) 基础语法

CSS 学习笔记 (1) 基础语法简介 CSS:层叠样式表(Cascading Style Sheets)用于控制网页的外观。 CSS 语法:先指定选择器,再给出键值对。 [选择器] {[属性]: [值]; }MDN 文档 链接:https://developer.mozilla.org/…

前端开发总结的一些技巧和实用方法

本文主要介绍一些JS中用到的小技巧和实用方法&#xff0c;可以在日常Coding中提升幸福度&#xff0c;也可以通过一些小细节来增加代码可读性&#xff0c;让代码看起来更加优雅&#xff0c;后续将不断更新 1.数组 map 的方法 (不使用Array.Map) Array.from 还可以接受第二个参数…

全网最全本科生必看TOP10 AI论文工具测评

全网最全本科生必看TOP10 AI论文工具测评 2026年本科生AI论文工具测评&#xff1a;为何值得一看 在人工智能技术不断渗透学术领域的今天&#xff0c;越来越多的本科生开始依赖AI工具提升论文写作效率。然而&#xff0c;面对市场上五花八门的AI写作平台&#xff0c;如何选择真正…

leetcode 1200

1200: 最小绝对差思路&#xff1a;排序后&#xff0c;只需考虑相邻元素之差把 arr 排序后&#xff0c;最小绝对差只能来自相邻元素&#xff08;不相邻的元素之差更大&#xff09;。遍历 arr 中的相邻元素 (x,y)&#xff0c;设绝对差为 diffy−x&#xff0c;当前最小绝对差为 mi…

一个程序模拟 直流绝缘监测仪,一个程序模拟 直流绝缘监测仪上位机

按照文档写了两个代码&#xff0c;模拟下面这个 直流绝缘检测仪

S7-1500作控制器S7-200SMART作智能设备

本文介绍了智能设备的功能&#xff0c;将S7-1500作为控制器&#xff0c;S7-200 SMART为智能设备&#xff0c;智能设备生成GSD文件&#xff0c;进行 PROFINET IO 通信的配置示例。 从 S7-200 SMART V2.5 版本开始&#xff0c;S7-200 SMART 开始支持做 PROFINET IO 通信的智能设…

低空经济新实践:无人机如何革新光伏电站巡检

引言&#xff1a;当低空经济遇见新能源革命在“双碳”战略引领下&#xff0c;光伏电站如雨后春笋般遍布神州大地。截至2023年底&#xff0c;我国光伏发电装机容量已突破6亿千瓦&#xff0c;连续多年位居全球首位。然而&#xff0c;随着光伏电站规模的急剧扩大&#xff0c;传统人…

DCDC同步降压:RT7272BGSP同步降压设计详解

目录 一、同步 Buck 降压工作原理 1. 基本拓扑结构 2. RT7272 控制模式 3. 核心工作流程 二、关键参数设计详解&#xff08;以 3.9V/3A 为例&#xff09; 1. 输出电压设计&#xff08;分压电阻 R13/R40&#xff09; 公式推导 选型建议 2. 电感设计&#xff08;L3&…

【2026最新】Directx dll修复工具是什么?DirectX修复工具下载保姆图文教程(附官网安装包),dll修复工具,一键解决dll文件丢失、c++异常、软件打不开等问题

相信很多朋友都会遇到“xxx.dll”丢失&#xff0c;软件启动不了、闪退等问题&#xff0c;说明你的系统缺少了支持的相关组件。今天要分享的软件是电脑DLL文件修复工具&#xff0c;强大且绿色&#xff0c;一键解决电脑dll文件丢失&#xff0c;C异常。DirectX修复工具是一款专门给…

14-机器学习与大模型制作数学教程-第1章 1-6 费马定理与极值判定

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

P1024 [NOIP 2001 提高组] 一元三次方程求解(1.26)

点击查看代码 #include<bits/stdc++.h> using namespace std;double a,b,c,d;double f(double x) {return a*x*x*x+b*x*x+c*x+d; }int main() {cin>>a>>b>>c>>d;int cnt=0;for(int i=-1…

EDC电子试验记录本,数字化科研时代的效率革命

在当今的科研与工业研发领域&#xff0c;数据是核心资产&#xff0c;而记录则是数据生命的起点。传统纸质实验记录本&#xff08;Paper Lab Notebook, PLN&#xff09;易污损、难追溯、不便共享的痛点日益凸显。据统计&#xff0c;科研人员平均每年因记录不规范、数据丢失等问题…

linux查询进程

通过端口找进程​lsof -i :8080 直接列出占用指定端口&#xff08;如8080&#xff09;的进程信息。精确快捷&#xff0c;信息直观&#xff08;进程名、PID、用户等&#xff09;。netstat -tunlp | grep 8080 -tunlp&#xff1a;显示TCP/UDP监听端口及关联进程&#xff0c;再…

python-Dgango项目收集静态文件、构建前端、安装依赖

数据平台项目&#xff08;pythondjangoreact&#xff09;后端&#xff1a;查看环境&#xff1a; conda env list先激活环境: conda activate unlabel (unlabel) PS D:\unbel_school> python .\label_studio\manage.py runserver 0.0.0.0:28080 加上…

实用指南:【C++初阶】vector容器的模拟实现,各接口讲解

实用指南:【C++初阶】vector容器的模拟实现,各接口讲解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas…

Linux、Windows常用命令

目录 windows常用命令 linuxl常用命令 windows常用命令 netstat -ano |findstr 28080 TCP 127.0.0.1:28080 0.0.0.0:0 LISTENING 10436 taskkill /f /t /pid 10436 linuxl常用命令 通过端口找进程​ lsof -i :8080 直接列出占用指定端口&a…

2026年1月26日

寒假的一些安排和必要事项 1.阅读构建之法类的书籍发3篇读书笔记(2月11日前 2.开发小程序 3.20篇以上的日记 4.其他科目的复习

2026年地坪漆国内TOP十大品牌推荐:从技术实力到场景适配的专业选型指南

2026年地坪漆国内TOP十大品牌推荐:从技术实力到场景适配的专业选型指南 在地坪漆行业,选择一个可靠的品牌,本质是为工业生产、商业运营或公共服务“买一份长期保障”——它不仅要解决地面耐磨、防滑、防腐等基础问…

生物等效性试验电子化记录,开启药品研发的智能合规新时代

在北京大学心血管研究所的实验室里&#xff0c;郭宇轩教授团队正在使用一个电子化平台&#xff0c;实验数据从记录到分析的全流程被实时捕捉和关联。研究数据资产的管理效率提升了30%以上。生物等效性试验是仿制药研发上市的关键环节&#xff0c;其数据的真实性、完整性与合规性…