当前位置: 首页 > news >正文

单调队列算法详解(附 Java 实战代码)

目录

一、什么是单调队列?

二、核心规则(以滑动窗口最大值为例)

三、经典例题:滑动窗口最大值

题目描述

Java 完整代码

代码核心解释

四、扩展:滑动窗口最小值

五、单调队列适用场景

六、总结


一、什么是单调队列?

单调队列= 队列 + 队列内元素严格单调递增 / 递减,是一种双端队列(Deque)实现的特殊数据结构。

核心特性:

  1. 队列头部始终是当前窗口 / 区间的最优值(最大值 / 最小值)
  2. 队列尾部用于添加新元素,维护单调性
  3. 插入 / 删除操作均为O(1),整体处理数组时间复杂度O(n)

它的核心用途:解决滑动窗口最值问题(暴力法 O (n・k),单调队列优化到 O (n))。


二、核心规则(以滑动窗口最大值为例)

我们维护一个单调递减队列

  1. 入队:新元素从队尾入队,把所有比它小的元素全部弹出(这些元素不可能成为后续窗口的最大值),再加入新元素下标
  2. 出队:如果队首元素下标超出窗口左边界,从队首弹出
  3. 取值:窗口形成后,队首元素就是当前窗口最大值

三、经典例题:滑动窗口最大值

题目描述

给定数组nums,大小为k的滑动窗口从数组最左侧移到最右侧,返回每个窗口的最大值。

示例:输入:nums = [1,3,-1,-3,5,3,6,7],k = 3输出:[3,3,5,5,6,7]

Java 完整代码

import java.util.ArrayDeque; import java.util.Deque; public class MonotonicQueue { public int[] maxSlidingWindow(int[] nums, int k) { // 边界判断 if (nums == null || nums.length == 0 || k <= 0) { return new int[0]; } int n = nums.length; // 结果数组长度:n - k + 1 int[] res = new int[n - k + 1]; int index = 0; // 双端队列:存储元素下标(方便判断是否超出窗口) Deque<Integer> deque = new ArrayDeque<>(); for (int i = 0; i < n; i++) { // 规则1:队首元素超出窗口左边界,移除 // 窗口左边界 = i - k + 1,队首 < 左边界 则过期 while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) { deque.pollFirst(); } // 规则2:维护单调递减队列 // 新元素 >= 队尾元素,队尾弹出(不可能成为最大值) while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) { deque.pollLast(); } // 加入当前元素下标 deque.offerLast(i); // 规则3:窗口形成后(i >= k-1),记录队首最大值 if (i >= k - 1) { res[index++] = nums[deque.peekFirst()]; } } return res; } // 测试 public static void main(String[] args) { MonotonicQueue mq = new MonotonicQueue(); int[] nums = {1,3,-1,-3,5,3,6,7}; int k = 3; int[] result = mq.maxSlidingWindow(nums, k); System.out.print("滑动窗口最大值:"); for (int num : result) { System.out.print(num + " "); } // 输出:3 3 5 5 6 7 } }

代码核心解释

  1. 队列存下标:方便判断元素是否超出窗口范围
  2. 维护递减:保证队首永远是当前窗口最大值
  3. 窗口形成条件i >= k-1,此时开始收集结果
  4. 时间复杂度:每个元素仅入队 / 出队一次,O (n)

四、扩展:滑动窗口最小值

只需修改维护规则,改为单调递增队列

// 维护单调递增队列(最小值) while (!deque.isEmpty() && nums[i] <= nums[deque.peekLast()]) { deque.pollLast(); }

五、单调队列适用场景

  1. 滑动窗口最值(最经典)
  2. 子数组区间最值问题
  3. 动态维护区间极值
  4. 优化 DP(单调队列优化 DP)

六、总结

  1. 本质:用双端队列维护单调序列,保证 O (1) 获取最值
  2. 核心操作:队首过期删除、队尾维护单调性、窗口形成取队首
  3. 优势:把 O (n・k) 暴力优化到 O (n)
  4. Java 实现:用ArrayDeque存下标,效率最高
http://www.zskr.cn/news/1381237.html

相关文章:

  • 基于ESP8266与DS18B20构建本地Wi-Fi温度监测系统
  • EEG深度学习优化器对比:从Adam到SGD的实战选型指南
  • 正点原子MiniFly飞控源码实战:从PID参数配置到定点悬停调试全流程
  • 2026低空治理新需求下的平台供应商推荐:黑飞监测预警系统能力观察 - 品牌2025
  • Awoo Installer:让Switch游戏安装变得简单高效的终极解决方案
  • Claude Code + LM Studio + CC-Switch 本地自动化编程部署指南
  • Windows 11 LTSC安装微软商店的终极解决方案:3步恢复完整应用生态
  • Frida Android动态插桩实战:绕过SSL Pinning与加固App Hook
  • 为静态网站生成器配置自动化AI内容摘要的简易方案
  • 基于ESP32与空气质量API的智能环境灯设计与实现
  • 为什么你的Midjourney输出总带“脏噪”?揭秘底层渲染管线中未公开的noise injection节点与4种绕过策略
  • Windows 11系统瘦身大作战:5分钟让你的电脑重获新生
  • 企业法务紧急通知:DeepSeek最新v2.3协议识别引擎已覆盖Rust/Cargo生态,错过本次升级将丧失GPLv3兼容审计资质
  • 揭秘Midjourney云雾渲染失效真相:3大隐性提示词冲突、2类SDXL迁移兼容漏洞及实时雾浓度校准公式
  • VMware Workstation Pro 17免费密钥终极指南:快速激活虚拟化神器
  • flowcontainer实战:加密流量特征工程的高效提取方案
  • Godot 2D随机地图三大静默故障:黑屏、穿墙、寻路失败的根源与修复
  • 基于Arduino Uno与MQ-2传感器的智能气体检测报警系统DIY全攻略
  • 机器学习赋能矩方法:破解稀薄气体强非平衡流动模拟难题
  • 为现有OpenAI兼容应用迁移到Taotoken的步骤指南
  • OpenCore Legacy Patcher技术突破:老旧Mac设备系统兼容性实战指南
  • 如何快速解密QQ音乐、网易云音乐等平台的加密音频文件?终极免费解决方案
  • 三步免费获取百度文库文档:浏览器控制台脚本实用指南
  • UOP MTO vs. 大连化物所DMTO:年产40万吨烯烃项目,工艺路线到底该怎么选?
  • 前景理论(Prospect Theory)深入扩展:数学公式、代码模拟、实验案例、AI结合及理论对比
  • 终极Obsidian笔记系统:如何用kepano-obsidian模板轻松管理你的数字生活
  • 5分钟快速上手res-downloader:跨平台资源下载工具的完整指南
  • Lovable后端集成安全红线清单,含OAuth2.1动态客户端注册、JWT密钥轮转、敏感头过滤(CWE-522/OWASP API Top 10对齐版)
  • 实战指南:基于YOLOv5的FPS游戏AI瞄准系统深度解析与高效应用
  • UE5高精度长度测量系统架构解析:定位球、射线检测与鼠标映射