【力扣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)

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

相关推荐
XINVRY-FPGA2 小时前
XC7Z010-2CLG400I Xilinx Zynq-7000 FPGA
arm开发·嵌入式硬件·算法·fpga开发·硬件工程·dsp开发·fpga
承渊政道2 小时前
【贪心算法】(经典实战应用解析(四):分发饼干、最优除法、跳跃游戏、跳跃游戏Ⅱ、加油站)
数据结构·c++·算法·leetcode·贪心算法·动态规划·哈希算法
m0_629494732 小时前
LeetCode 热题 100-----24.回文链表
数据结构·算法·leetcode·链表
爱怪笑的小杰杰2 小时前
Leaflet 实现轨迹拐角自动圆弧化:基于球面几何的高精度平滑算法
前端·javascript·算法·无人机
ccLianLian3 小时前
图论·刷题总结
算法·深度优先·图论
_深海凉_3 小时前
LeetCode热题100-二叉树展开为链表
算法·leetcode·链表
ECT-OS-JiuHuaShan3 小时前
什么是认知,认知的本质是什么?
数据库·人工智能·算法·机器学习·数学建模
Black蜡笔小新3 小时前
自动化AI算法训练服务器DLTM:筑牢数据安全底座,赋能企业AI高效安全落地
人工智能·算法·自动化
月殇_木言3 小时前
算法进阶(上)
算法