问题描述:

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

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

就像下面这样(图片来自力扣)

怎么办?

假设,有这么一个队列。
队列是有序的,而且,随着滑动窗口的移动,窗口内的队列始终有序(递减)。

那我们是不是只要每次滑动窗口移动以后返回窗口内队列的队头元素就可以啦!!!

简直很舒服。

所以,现在核心问题是:怎样才能让窗口里那个队列始终保持队列单调呢?

那什么时候队列的单调性可能会改变呢?

很明显,当滑动窗口移动后,最队头元素出去了,队尾按理说要添加进来一个元素。

但是,这个元素加入到对尾是不是就不递减了呢?

这个真说不来。但是我们可以定义一个新的push()入队函数,保证入队以后,队列还是递减的就行啦。

下面看入队且能保证队列单减的方法。

入队push()的原则

若push的数值大于入口(队尾)的元素值,
那么就直接将队列后端(队尾)的数值弹出。
如果一直大于,就一直弹对尾元素;
直到要push的数值比对尾元素的值小。

(一个是最大的,一个是次大的)

出队pop()的原则

每次弹出的时候,
检查当前窗口要移除的元素value **(就是窗口最左边的元素)**和队列出口(队头)元素的大小,
若两者相等(要弹出的元素和队头元素)
那么,弹出。

出队这里要注意:并不一定每次往后移动都有元素弹出去的,至于为什么,可以跟着下面的例子模拟一下就能知道了。

其实只有一种情况会使用下面这个pop函数出队:那就是队头元素,恰好也在滑动窗口的最左边。

因为有的时候最大值在中间,那可能窗口左边的值在中间最大值进队的时候就已经删除了,所以这时候是没必要再做删除操作的。

举个例子:
比如窗口我空中括号表示,队列我用圆括号表示;
[ , , (5,4)]
上面这个窗口里有4个元素,但是队列里只有2个元素,这时候窗口往右边移动,次要删除队列左边的5吗?
明显不需要。
因为窗口下次移动的时候,窗口最左边的元素已经弹出去了,所以直接移动就行了。

但是,如果是下面这种情况就要出队了:
[(5, 4), , ]

语言描述令人头昏脑涨,还是举个例子模拟一下吧。模拟完了再来看上面的描述。

模拟:

数组:nums = [1,3,-1,-3,5,3,6,7]
滑动窗口:k = 3
滑动窗口丛0个元素开始添加元素,滑动窗口的最大值是从窗口里有3个元素以后开始算的。
所以滑动窗口第一个最大值是第三行的3,前两行不算。
前两行只是为了模拟代码执行的流程。

要push的值 因为push而弹出的值 队列内的元素(左队头右队尾) 滑动窗口最左侧值
1 1 1
3 1 3 1
-1 3,-1 -1
-3 3,-1,-3 3
5 3,-1,-3 5 -1
3 5,3 -3
6 5,3 6 5
7 6 7 3

由上面的模拟可以看出,队列内队头元素始终是滑动窗口的最大值

难点:

要分清楚 滑动窗口里的元素

单调队列里元素的关系

  • 单调队列的元素肯定在滑动窗口里,但是,是滑动窗口的子集
  • 滑动窗口只保留最大的几个元素,肯定会保留这个窗口里的最大元素,至于还能保留几个其他元素,这个要看新添加进来的元素的大小,通过push函数,就可以把小于新添加元素的队内其他元素全部删除。
    若新添加的元素足够大,那队内显然只会剩下他一个,他也就是队头
  • 队列往右边移动的时候,也非常关键
    • 若,此时滑动窗口最左边的元素恰好就是队头元素(即队列最大元素),那就得删除

总之,push函数就保证了,在这个滑动窗口里,单调队列的队头就是最大元素
pop函数保证了,滑动窗口正常移动
二者双剑合璧,找出窗口里最大的值

下面是代码实现

#include <string>
#include <queue>
#include <iostream>using namespace std;class Solution {private:class MyQueue{//自己定义一个单调队列的专有操作public://使用deque来实现单调队列deque<int> que;/*1.pop(value)弹出函数:*什么情况下才能弹出呢?*当滑动窗口最左边的元素 和*单调队列最左边的元素(也就是队头元素)相等的时候,弹出。*否则,就不做任何操作,不弹出任何东西。*当然,当点掉队列不为空的时候,也是没法弹出的。*/void pop(int value) {//front()函数:取队列的队头元素if (!que.empty() && value == que.front()) {      //弹出队头元素que.pop_front();}}//2.push(value)元素进队函数/*什么情况下可以进入队列呢?*进入队列要进行那些操作才能保持单调队列的单调减少呢?*如果,将要进入队列的元素,大于当前的对尾元素,*则pop_back(),把队的最后一个元素弹走。*继续判断,直到队尾的最后一个元素大于要加入的元素,或者队空了,则结束。*这样就可以保证,队里有最大的数,而且,这个数在队头,队头右边的数也是次大的。*保证了单调队列的单调性。*/void push(int value) {while (!que.empty() && value > que.back()) {que.pop_back();}//把比value小的弹出完以后,将valua放入队列中。que.push_back(value);}//最后,队头元素,这个元素,就是这个滑动窗口里最大的那个仔int front() {return que.front();}}
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {MyQueue que;vector<int> result;for (int i = 0;i < k; i++) {que.qush(nums[i]);}//result记录前k的元素的最大值result.push_back(que.front());for (int i = k; i <nums.size(); i++) {//注意,这里删除元素和加入元素的顺序不能反了,先加入pop弹出元素再push加入元素que.pop(nums[i - k]);//滑动窗口移除最前面元素que.push(nums[i]);//滑动窗口加上后面对应的元素result.push_back(que.front());//记录对应的最大值}     return result;}
};

栈和队列6:滑动窗口最大值相关推荐

  1. 环形数组队列求滑动窗口最大值

    给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位.返回滑动窗口中的最大值. 示例: 输入: nu ...

  2. 栈和队列之生成窗口最大值数组

    package com.chenyu.zuo.stackAndQueue;import java.util.LinkedList;/*** 题目:有一个整形数组,arr和一个大小为w的窗口从数组的最左 ...

  3. Suzy找到实习了吗Day 13 | 栈和队列结束啦 239. 滑动窗口最大值,347. 前 K 个高频元素

    day 13 239. 滑动窗口最大值 Python的Deque模块详解 solution 我复制的,好难不会写 347. 前 K 个高频元素(一刷我没有用栈,用的哈希法) solution(hash ...

  4. (补)算法训练Day13 | LeetCode150. 逆波兰表达式求值(栈应用);LeetCode239. 滑动窗口最大值(单调队列);LeetCode347. 前K个高频元素(小顶堆,优先级队列)

    目录 LeetCode150. 逆波兰表达式求值 1. 思路 2. 代码实现 3. 复杂度分析 4. 思考 LeetCode239. 滑动窗口最大值 1. 思路 2. 代码实现 3. 复杂度分析 4. ...

  5. leetcode 239. Sliding Window Maximum | 239. 滑动窗口最大值(单调栈,窗口内最大最小值更新结构)

    题目 https://leetcode.com/problems/sliding-window-maximum/ 题解 窗口内最大最小值更新结构,单调栈问题,左神视频讲过,<程序员算法面试指南& ...

  6. 力扣239. 滑动窗口最大值(自定义排序队列)

    239. 滑动窗口最大值 //实现功能:peek()取得队列的最大值,比最大值先添加进来的删除,后添加进来的保留 class Mydeque{Deque<Integer> deque;pu ...

  7. 【LeetCode】【HOT】239. 滑动窗口最大值(双向队列)

    [LeetCode][HOT]239. 滑动窗口最大值 文章目录 [LeetCode][HOT]239. 滑动窗口最大值 package hot;import java.util.Arrays; im ...

  8. 嗯,查询滑动窗口最大值的这4种方法不错....

    作者 | 王磊 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone) 本文已收录至 Github<小白学算法>系列:https://gith ...

  9. 剑指offer:滑动窗口最大值

    文章目录 暴力做法 单调队列 题目来源 暴力做法 直接遍历所有的滑动窗口,分别判断最大值. 时间复杂度O(n * k) 空间复杂度O(n) class Solution {public:// 时间复杂 ...

最新文章

  1. 使用Jupyter Notebook编写技术文档
  2. 整洁代码之道——重构
  3. javascript中match方法和exec()方法详解与深度区别(非原创)
  4. [云炬创业基础笔记] 第三章测试3
  5. [原]排错实战——通过对比分析sysinternals事件修复程序功能异常
  6. 不存在_施文忠 | ”存在“与“不存在”——巴蜀文明概论
  7. leetcode - 1024. 视频拼接
  8. 三维旋转四元数系列(1.复数与二维旋转)
  9. asp.net中使用#include语法将文件添加到页面
  10. 群签名和环签名的区别_Monero技术详解(三):核心技术—环签名(1)
  11. kubernetes v1.8.8中 RBAC DENY 解决办法
  12. linux(Ubuntu)下Navicat的激活与无限试用
  13. bilibili老版本_bilibili旧版本
  14. 正确认识使用Word模板
  15. cents7 mysql数据库安装和配置
  16. 国外也有“天价流量账单” 看看都什么情况?
  17. 超级跑车法拉利的历史
  18. 综合应用 -- 购物车
  19. git本地无法上传到远程的问题解决方法
  20. 【金猿产品展】荣联冷冻电镜数据分析平台——助力生物医疗科研创新

热门文章

  1. 使用H5 Canvas 在微信中合成海报(背景+logo+昵称)
  2. Reversed Numbers
  3. 吐槽大会4_吐槽大会4什么时候播 吐槽大会第四季嘉宾都有谁?
  4. 时钟电路程序设计c语言,STC89C52单片机简易时钟程序电路设计(附源代码和电路图)...
  5. 年纪轻轻记忆力就衰退得厉害,我还有救吗?
  6. Windows 上最好用的 5 个 EPUB 阅读器(转载)
  7. 深度学习之目标检测(八)图片标注
  8. 良哥于11月23日下午经典语录!!哇哈,我想笑
  9. lombok的setter和getter失效问题
  10. 2021爱智先行者——EdgerOS Spirit 1深度使用体验与EdgerOS应用开发实践