剑指offer 59:滑动窗口的最大值

滑动窗口的最大值

题目:
给定一个长度为 n 的数组 nums 和滑动窗口的大小 size ,找出每一个滑动窗口里数值中的最大值。

例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个:
{[2,3,4],2,6,2,5,1},
{2,[3,4,2],6,2,5,1},
{2,3,[4,2,6],2,5,1},
{2,3,4,[2,6,2],5,1},
{2,3,4,2,[6,2,5],1},
{2,3,4,2,6,[2,5,1]}。

在这里插入图片描述

隐含条件:双端队列,要保持单调递减,而当后进来的比先进来的都大了,那么先进去的那些就没有可能再成为最大,也就无用了!即当新加入元素比之前的还大时,直接弹出之前的元素!

思路:
用双端队列表示滑动窗口(先进先出的特性),注意队列存储的是下标而不是元素的大小!

  1. 清理: 清理窗口前面的元素,即过期元素(当队列头部元素索引 ≤ i-k时,弹出头部元素) ,以保持窗口宽度k
  2. 维护:用单调队列来维护滑动窗口(元素的大小单调递减),当不满足单调递减时就清理掉前面小的元素,使用while循环,直到队列单调递减(即新加入的元素要小于 队列尾部才能维持单调递减!若新加入的元素大于队列尾部,则直接弹出队列尾部!
  3. 新元素的索引入队列
  4. 队列最左边的元素就是滑动窗口的最大值 !每次返回最左边的元素即可

实现:

public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int k) {
        if(num.length==0||k==0){  // 安全校验
            return null;
        }
        
        ArrayDeque<Integer> deque=new ArrayDeque<>(); //初始化双端队列
        int n=num.length;
        ArrayList<Integer> list=new ArrayList<>();
        for(int i=0;i<n;i++){ // i是每轮新加入的索引
            //注意队列存的是索引!不是元素大小
            //1. 清除过期元素,当队列头部≤ i-k 则需要弹出 (要清除就要保证队列不为空)
            while(!deque.isEmpty() && deque.peek()<=i-k){ 
                deque.poll();    
            }
            //2. 维护单调递减,新加入的要小于队列尾部,若新加入的大于队列尾部则弹出队列尾部!直到新加入的小于队列尾部为止!  ※※※
            while( !deque.isEmpty() && num[i]>num[deque.peekLast()] ){
                deque.pollLast(); // 弹出last直到新进来的都小于last
            }
            //3. 新元素的索引的入队列
            deque.add(i); //存的是索引!
            //存入窗口内最大值,由于队列是是单调递减的,即添加每一轮中队列中头部到list中即可
            if(i>=k-1){ // 达到窗口宽度开始将队列头节点存入list
                list.add(num[deque.peek()]);  // 此处不能用poll !
            }
        }
        return list;   
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值