滑动窗口leetcode

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

返回滑动窗口最大值。

示例:

输入: 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

注意:

你可以假设 总是有效的,1 ≤ k ≤ 输入数组的大小,且输入数组不为空。

进阶:

你能在线性时间复杂度内解决此题吗?

****************************************************************************************************************

看完题目可知 数组的长度为n, 窗口的长度为k,则从左到右,一共会有n-k+1次滑动,也就是返回的最大值数组长度为n-k+1;

第一种想法是 遍历整个数组,对于每一次窗口里的元素再进行一次遍历取最大值,这样的时间复杂度为 O(n*k),题目要求尽量复杂度为线性,则考虑用双端队列

代码如下:

public class MaxSlidingWindow239 {

   public static int [] maxSlidingWindow(int [] a, int k){

      if(a == null || k <= 0){
         return new int[0];
      }

      int n = a.length;
      //共有n-k+1次滑动
      int [] res = new int[n-k+1];
      //保存元素下标
      Deque<Integer> q = new ArrayDeque<Integer>();

      //res数组的下标指针
      int resIndex = 0;

      for (int i = 0; i < n ; i++) {

         /**
          * 确保q中保存的下标长度小于等于窗口的长度,
          * i-k+1为当前元素作为窗口右侧边界时,窗口左侧边界的元素下标,如果队列中的第一个元素的下标小于左侧边界,
          * 则说明队列中保存的下标过多,需要保证队列中的下标个数<=k
          */
         while (!q.isEmpty() && q.peekFirst() < i-k+1){
            q.poll();
         }

         /**
          * 如果队列中最后一个下标对应的元素<a[i],则循环移除最后一个下标,
          * 直到保证队列的第一个下标对应的元素为当前窗口的最大值
          */
         while (!q.isEmpty() && a[q.peekLast()] < a[i]){
            q.pollLast();
         }

         //队列中加入当前元素的下标
         q.offer(i);

         /**
          * i<k-1时,窗口刚开始滑动时,元素没有填充满窗口,无法选出最大值
          */
         if(i >= k-1){
            res[resIndex++] = a[q.peek()];
         }
      }
      return res;
   }

   public static void main(String[] args) {
      int[] a = {6, 3, 4, 2, 5, 9, 1};
      //窗口大小为3
      int k = 3;
      int [] max = maxSlidingWindow(a, k);
      System.out.println("滑动窗口的最大值:");
      Arrays.stream(max).forEach(System.out::println);
   }

输出:滑动窗口的最大值:
6
4
5
9
9

 

ps:附上队列的部分函数说明

/**
 * 队列的方法介绍
 * add        增加一个元索             如果队列已满,则抛出一个IIIegaISlabEepeplian异常
 * remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常
 * element  返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常
 * offer       添加一个元素并返回true       如果队列已满,则返回false
 * poll         移除并返问队列头部的元素    如果队列为空,则返回null
 * peek       返回队列头部的元素             如果队列为空,则返回null
 * put         添加一个元素                      如果队列满,则阻塞
 * take        移除并返回队列头部的元素  
 */

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值