【力扣hot100:239. 滑动窗口最大值】

题目链接:239. 滑动窗口最大值

这道题是找每个固定滑动窗口的最大值,开始我的思路是这样的:

  • 维护一个大顶堆,用定长滑动窗口的写法,大顶堆的顶部就是最大值,可以直接通过peek()获取顶部的值,代码如下:

    java 复制代码
    class Solution {
      public int[] maxSlidingWindow(int[] nums, int k) {
        int mx = Integer.MIN_VALUE;
        //创建一个大顶堆
        PriorityQueue<Integer> pq = new PriorityQueue<>((a,b) -> b - a);
        int left = 0;
        List<Integer> ans = new ArrayList<>();
        for (int right = 0; right < nums.length; right++){
          //入堆
          pq.add(nums[right]);
          //更新最大值
          mx = pq.peek();
    
          if (right - left + 1 < k){
            continue;
          }
    
          //次数够k了
          ans.add(mx);
    
          //出堆
          pq.remove(nums[left]);
          left++;
        }
        return ans.stream().mapToInt(Integer::intValue).toArray();
      }
    }

但是这个方法是会超时的,超时的原因在于pq.remove(nums[left])需要线性查找元素,时间复杂度是 O(k) 。加上外层循环执行 n 次,总复杂度变为 O(n × k),因此导致了超时

我们可以使用双端队列的写法:

思路如下:

  • 维护一个双端队列
  • 右边负责入队,并且维护单调性(保证从左到右是递减的)
  • 左边负责出队
  • 记录答案

具体代码如下:

java 复制代码
class Solution {
  public int[] maxSlidingWindow(int[] nums, int k) {
    int n = nums.length;
    int []ans = new int[n - k + 1];
    //创建队列,存储下标
    Deque<Integer> q = new ArrayDeque<>();

    for(int i = 0; i < n; i++){
      //右边入队,维护单调性
      while(!q.isEmpty() && nums[i] >= nums[q.getLast()]){
        q.removeLast();
      }
      q.addLast(i);//保存下标,下面可以判断队首是否离开窗口

      //左边出队(窗口最大值就在左边)
      int left = i - k + 1;//窗口左边下标
      if(q.getFirst() < left){//窗口左边出队,因为窗口每次只滑动 1 步,每轮循环最多只有 1 个 旧下标会移出窗口,所以不需要用while,当然写while也可以过
        q.removeFirst();
      }
      //记录答案
      if(left >= 0){
        ans[left] = nums[q.getFirst()];
      }
    }
    return ans;
  }
}

通过代码我们也不难发现,关键是这两点:

  • i跟left负责维护有效窗口,通过判断队首下标是否小于左边界,确保最大值在当前窗口内
  • 队列存储下标,负责维护单调性,队首始终是当前窗口的最大值下标

虽然这个方法里面也嵌套了while循环,但是这个方法的时间复杂度不是O(n x k),因为每个下标最多入队出队一次,整个过程中总次数最多不超过2n次,这是线性的,所以总时间复杂度是O(n)

如果这篇文章对你有帮助,欢迎点赞、评论、关注、收藏。你们的支持是我前进的动力!

相关推荐
2601_954526754 分钟前
【硬核长文】从卡门涡街物理方程到边缘网关温压补偿算法:工业蒸汽测控实战,深度解密靠谱的涡街流量计厂家有哪些
算法
吞下星星的少年·-·19 分钟前
牛客技能树:区间翻转
算法·滑动窗口
tkevinjd1 小时前
力扣148-排序链表
算法·leetcode·链表
qeen872 小时前
【C++】vector的模拟实现详解(二)
c++·学习·算法·迭代器·stl
zzz_23683 小时前
码上面试平台测试报告:功能、后台管理、异常状态与 JMeter 性能验证
jmeter·面试·职场和发展
沉迷学习 日益消瘦3 小时前
4 净资产趋势可视化:SVG 图表 + 手势交互 + 降采样算法
算法·交互
浩哥学JavaAI14 小时前
2026年最新AI agent面试(10)_通信与行业动态
人工智能·面试·职场和发展
可编程芯片开发14 小时前
基于MATLAB的PEF湍流风场生成器模拟与仿真
算法
罗西的思考15 小时前
【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (9)--- Reward Judging
人工智能·算法·机器学习
Mr.HeBoYan16 小时前
一次持续三天才出现的丢包故障——深入解析 DPDK Memory Ordering、rte_ring 与 CPU Memory Barrier (下)
linux·网络·算法·架构·dpdk