代码随想录栈与队列——滑动窗口最大值

题目

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

返回滑动窗口中的最大值。

在这里插入图片描述

思路

单调队列的思想

单调队列:又名双端队列,具有一定单调性的队列(单调递增,单调递增),可以从队列的首尾进出元素

只维护可能成为最大值的元素

简单来说,就是,保证队列出口最大的元素,队列中前面的元素比后面进来的元素小的话就全部挤掉,后面进来的元素比前面的元素小的话就保留

比如对于窗口{2,3,5,1,4}中的元素,单调队列只需要维护{5,4}就够了,其中2和3从队头出队列了,1从队尾出队列了,队列中只留下5,4,保证单调队列里单调递减,此时队列出口元素就是窗口最大元素

(1)deque 内 仅包含窗口内的元素 ⇒ 每轮窗口滑动移除了元素 nums[i−1],需将 deque 内的对应元素一起删除。
(2)deque内的元素 非严格递减 ⇒ 每轮窗口滑动添加了元素 nums[j+1],需将 deque 内所有 <nums[j+1] 的元素删除。

算法流程:

(1)初始化: 双端队列 deque,结果列表 res ,数组长度 n

(2)滑动窗口: 左边界范围 i∈[1−k,n−k],右边界范围 j∈[0,n−1]

如下图所示:
在这里插入图片描述
在这里插入图片描述

a)若 i>0 且 队首元素 deque[0] = 被删除元素 nums[i−1](即滑出窗口的元素):则队首元素出队;

b)删除 deque 内所有 <nums[j]的元素,以保持 deque递减;

c)将 nums[j]添加至 deque 尾部;

d)若已形成窗口(即 i ≥ 0 ,所谓形成窗口就是):将窗口最大值(即队首元素deque[0])添加至列表 res

(3)返回值: 返回结果列表 res

简单来说就是,不断入队列,只要我比你大,你给我出去;我比你小,就跟在你后面,最终保持递减(这里要注意,1是从队尾出的,图画的有点问题,4是比较还没入队列,先出1在入4的):
在这里插入图片描述

java代码如下:

//要注意,是先更新窗口,然后根据弹出窗口的值,和新加入窗口的值,再去更新单调队列中的值
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 0 || k == 0) 
        	return new int[0];
        Deque<Integer> deque = new LinkedList<>();
        int[] res = new int[nums.length - k + 1];//数组 nums的长度为 n ,则共有 (n−k+1) 个窗口
        for(int i = 1 - k, j = 0; j < nums.length; i++, j++) {//窗口开始滑动,最开始的范围为[1-k,0]
            // 因为每轮窗口滑动移除的元素为 nums[i−1](即窗口的左边界nums[i]的前一个元素),需将 deque 内的对应元素一起删除,即删除 deque 中对应的 nums[i-1]
            if(i > 0 && deque.peekFirst() == nums[i - 1])
                deque.removeFirst();
            // 保持 deque 递减,nums[j]为窗口右边界,即加入窗口的新元素
            while(!deque.isEmpty() && deque.peekLast() < nums[j])//如果当前队列的队尾小于要加入的新元素
                deque.removeLast();//则删除队尾元素,维持队列递减
            deque.addLast(nums[j]);//加入新元素
            // 记录窗口最大值
            if(i >= 0)//当形成窗口时
                res[i] = deque.peekFirst();//将窗口最大值,即队首元素 deque[0](因为是递减),添加至列表res
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HDU-五七小卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值