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

单调队列+滑动窗口

对应力扣239滑动窗口的最大值

给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值

暴力解法:

  • 设置左右指针形成固定长度 k的窗口(左指针left,右指针right=left+k-1);
  • 遍历窗口内[left, right]的 k 个元素,找到并记录最大值;
  • 左右指针同时右移 1 位,重复步骤 2,直到窗口滑出数组末尾;
  • 最终将所有窗口的最大值组成数组返回。

时间复杂度为O(n×k)n为数组长度,k为窗口长度

/** * @param {number[]} nums * @param {number} k * @return {number[]} */ var maxSlidingWindow = function(nums, k) { const res = []; const n = nums.length; let left = 0; // 右指针最大为n-1,窗口左边界最大为n-k while (left <= n - k) { let right = left + k - 1; let max = nums[left]; // 遍历当前窗口,找最大值(你的核心思路) for (let i = left; i <= right; i++) { max = Math.max(max, nums[i]); } res.push(max); left++; // 指针右移,窗口滑动 } return res; };

为什么暴力法效率低?(重复计算是关键)

暴力法的致命问题是存在大量重复计算:窗口每次只右移 1 位,相邻两个窗口有 k-1 个元素是重叠的,但暴力法会重新遍历全部 k 个元素找最大值,浪费了重叠部分的计算结果

单调队列(双端队列 Deque)

要解决重复计算问题,核心是用一个特殊队列记录「窗口内可能成为最大值的元素下标」,让队列保持单调递减,这样队列队首永远是当前窗口的最大值下标,窗口滑动时只需维护这个队列,无需遍历窗口。

先理解:单调递减队列的核心规则

队列中存储的是nums 的元素下标(而非值),且满足:下标对应的值从队首到队尾严格单调递减(比如队列里的下标对应值是 [5,3,-1],而非 [3,5,-1])。

队列的3 个核心维护操作(窗口滑动时执行):

  1. 去尾:当新元素进入窗口时,若新元素值 ≥ 队尾下标对应的值,则队尾出队(因为该队尾元素在窗口内,不可能成为后续任何窗口的最大值,直接淘汰),重复此操作直到队列单调递减;
  2. 入队:将新元素的下标加入队尾,此时队列仍保持单调递减;
  3. 删头:若队首下标 ≤ 窗口左边界 - 1(说明队首元素已滑出窗口),则队首出队,保证队首始终在窗口内。
最优解核心步骤(全程只需遍历数组 1 次)
  1. 初始化双端队列 deque(存储下标)、结果数组 res;
  2. 遍历数组 nums 的每个元素,下标为i
    • 步骤 1:去尾→ 维护队列单调递减,淘汰比当前元素小的队尾;
    • 步骤 2:入队→ 将i加入 deque 队尾;
    • 步骤 3:删头→ 移除滑出窗口的队首下标;
    • 步骤 4:记录最大值→ 当i ≥ k-1(说明第一个窗口已形成),将nums[deque[0]](队首是窗口最大值下标)加入 res;
  3. 遍历结束,res 即为所有窗口的最大值数组。

用数组模拟双端队列(shift()删队首、pop()删队尾、push()入队尾)

/** * @param {number[]} nums * @param {number} k * @return {number[]} */ var maxSlidingWindow = function(nums, k) { const res = []; const deque = []; // 双端队列,存储nums的下标,保持单调递减 const n = nums.length; for (let i = 0; i < n; i++) { // 操作1:去尾 - 维护单调递减,淘汰比当前元素小的队尾 while (deque.length && nums[i] >= nums[deque[deque.length - 1]]) { deque.pop(); } // 操作2:入队 - 加入当前元素下标 deque.push(i); // 操作3:删头 - 移除滑出窗口的队首(窗口左边界为i-k+1) while (deque[0] <= i - k) { deque.shift(); } // 操作4:记录最大值 - 第一个窗口形成后(i>=k-1),队首即为当前窗口最大值 if (i >= k - 1) { res.push(nums[deque[0]]); } } return res; };

为什么左边界是i-k+1

你问的这个问题是滑动窗口的核心边界计算规则i-k+1当前遍历下标i作为窗口右边界时,窗口对应的左边界下标,核心推导基于「窗口长度固定为k+ 数组下标从 0 开始」两个前提,下面用大白话 + 数学推导 + 例子讲透,保证一看就懂!

一、核心前提(先记死,所有推导的基础)

  1. 力扣 239 题是固定长度滑动窗口,窗口内元素的个数严格等于k(比如k=3,窗口永远包含 3 个元素);
  2. 数组 / 字符串的下标从 0 开始(这是编程的通用规则,也是边界计算的关键);
  3. 我们遍历数组的下标i始终作为当前窗口的「右边界」(窗口的最后一个元素的下标)。

二、数学公式推导(10 秒看懂,最直观)

我们的目标是:已知窗口右边界下标i+ 窗口长度k,求窗口左边界下标left

第一步:先想「连续数字的个数」计算规则

对于任意连续的下标区间[left, i](left ≤ i),区间内的元素个数计算公式是:元素个数=i−left+1✅ 验证(下标从 0 开始):

  • 区间[0,2]2-0+1=3个元素(0、1、2),正确;
  • 区间[1,3]3-1+1=3个元素(1、2、3),正确;
  • 区间[2,4]4-2+1=3个元素(2、3、4),正确。
第二步:结合「窗口长度 = k」推导左边界

因为固定窗口的元素个数必须等于k,所以代入公式得:k=i−left+1将公式移项求解left(小学一元一次方程):left=i−k+1

这就是i-k+1数学由来,没有任何复杂逻辑,纯粹是「下标从 0 开始」的个数计算规则推导结果。

http://www.jsqmd.com/news/326830/

相关文章:

  • LED照明核心技术解析:光通量、显色指数与色温
  • Java计算机毕设之基于springboot的宠物领养及健康管理系统基于springboot+vue的宠物领养管理系统(完整前后端代码+说明文档+LW,调试定制等)
  • 【毕业设计】基于springboot的宠物领养及健康管理系统(源码+文档+远程调试,全bao定制等)
  • Java毕设项目推荐-基于springboot+bs架构的校园活动管理系统基于bs架构的校园活动管理系统【附源码+文档,调试定制服务】
  • 【个人成长笔记】VI编辑器完整使用说明书(实操篇)
  • 计算机Java毕设实战-基于springboot+bs架构的校园体育器材管理系统设计与实现实现器材借用、归还、损坏等多功能管理。【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 【计算机毕业设计案例】基于springboot的宠物领养及健康管理系统(程序+文档+讲解+定制)
  • 气泡动力学资料大全
  • 基于机器学习的负荷曲线聚类:从经典到创新
  • 风控模型不是“神谕”:那些模型无法告诉你的决策盲区
  • 【课程设计/毕业设计】基于springboot架构的校园体育器材管理系统设计与实现基于springboot+bs架构的校园体育器材管理系统设计与实现【附源码、数据库、万字文档】
  • 加密账本UI设计
  • 一套可复用的高质量特征挖掘方法论
  • Java毕设项目:基于springboot的个性化推荐电商平台的设计与实现(源码+文档,讲解、调试运行,定制等)
  • 给app添加血压记录
  • Helix 02 :移动+操作融合,解锁人形机器人全身控制的VLA模型
  • Java计算机毕设之基于springboot的个性化推荐电商平台的设计与实现基于SpringBoot的网上购物商城设计与实现(完整前后端代码+说明文档+LW,调试定制等)
  • 如何用 Python 对接实时股票 API 并构建预警系统?:实战分享
  • 文件名速提助手:全自动扫描目录子目录文件名一键导出TXT清单文件名提取软件
  • 【毕业设计】基于springboot的个性化推荐电商平台的设计与实现(源码+文档+远程调试,全bao定制等)
  • Java计算机毕设之基于Springboot的体育器材入库、出库、维修、报废管理系统基于springboot+bs架构的校园体育器材管理系统设计与实现(完整前后端代码+说明文档+LW,调试定制等)
  • Elasticsearch入门指南:从安装到实战
  • jsp高考辅助推荐系统o4udh-程序+源码+数据库+调试部署+开发环境
  • PolarDB-X 集群暂停 / 恢复完整运维文档
  • 【计算机毕业设计案例】基于springboot电商个性化推荐系统设计与实现基于springboot的个性化推荐电商平台的设计与实现(程序+文档+讲解+定制)
  • jsp钢铁集团公司安全管理系统e2160(程序+源码+数据库+调试部署+开发环境)
  • 【计算机毕业设计案例】基于SpringBoot+Vue校园体育器材管理系统基于springboot+bs架构的校园体育器材管理系统设计与实现(程序+文档+讲解+定制)
  • 【毕业设计】基于springboot的员工绩效管理系统的设计与实现(源码+文档+远程调试,全bao定制等)
  • React Native for OpenHarmony:Image 组件的加载、渲染与性能优化全解析
  • 告别知识孤岛!Wiki.js打造知识库,cpolar实现随处可用。