滑动窗口简单概念

滑动窗口是我们假想出的一种数据结构,我们在这篇文章实现的窗口,能较快速的求区间最大最小值

在一些区间不回退的题目中运行效率也十分优秀

设窗口的左边界为l,右边界为r,(规定l<=r恒成立)

我们可以通过滑动右边界,从窗口的右边进入数字

也可以通过滑动左边界,从窗口左边出数字

滑动窗口求区间最大值(leetcode239)

原题链接

题目描述:

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

思路求解

我们可以通过双端队列来实现我们求最大值窗口的结构,双端队列中存储数组中的下标

双端队列中必须始终维持根据下标对应的数字由大到小的顺序

不断的移动窗口,若进入的数会打破由大到小的平衡(即新数字大于队列末),队尾就不断出数字,直到满足双端队列的要求为止,再把当前数字插入

动图演示:

它可以表示在固定大小窗口中,只要窗口中包含这个数字,那么这个窗口的最大值永远队头

直到窗口中没有了这个最大值,那么把它从左边弹出

代码实现及注释:

class Solution {public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n=nums.size();vector<int>ans;deque<int>qmax;//维持最大值的队列for(int r=0;r<n;r++){while(!qmax.empty()&&nums[qmax.back()]<=nums[r]){qmax.pop_back();//这是维持队列由大到小的结构//将队尾所有比新数字小的数字全部弹出}qmax.push_back(r);if(qmax.front()==r-k){qmax.pop_front();//这是最大值对应下标已经不在窗口中的情况//因为r-l=k}if(r>=k-1){ans.push_back(nums[qmax.front()]);//窗口已经成型,就直接加入数字}}return ans;}
};

求满足要求的子数组个数

题目描述:

给定一个数组arr和一个整数sum

若一个子数组(必须连接)满足子序列最大值-最小值<=sum,则称这个子数组符合要求

返回所有符合要求的子序列个数

思路求解:

我们可以先甩出两个结论:

  • 如果某个子数组满足要求,那么这个子数组的子数组都符合要求
  • 如果某个子数组不满足要求,那么以它为子数组的数组都不符合要求

为什么?

我们知道,我们最终要求的是max-min

如果满足要求了,那么max-min<sum是应该成立的

显然易见,它的子数组最大值只会比这个数组的最大值小,最小值只会比这个数组的最小值大,

所以这个情况下,max-min是只会减少的

不满足要求的同理可证

所以我们可以这样:

初始先把窗口放在最左边,维持窗口最大和最小值,不断更新窗口右边界,直到不满足要求

根据结论1,从l开始的所有子数组都满足要求**(l到l+1;l到l+2;l到l+3…等子数组)**

根据结论1,我们在更新l的时候,可以不用更新r

代码和注释:

 int AllLessNumSubArray(vector<int>& nums, int sum){int n = nums.size();deque<int>qmax;deque<int>qmin;int ans = 0;int r = 0;for (int l = 0; l < n; l++){while (r < n){while (!qmax.empty() && nums[qmax.back()] <= nums[r]){qmax.pop_back();}qmax.push_back(r);while (!qmin.empty() && nums[qmin.back()] >= nums[r]){qmin.pop_back();}qmin.push_back(r);//以上是维持最大最小队列//以下是滑动窗口if (nums[qmax.front()] - nums[qmin.front()] <= sum){r++;}else{break;}}ans += r - l;//更新过期元素if (qmax.front() == l){qmax.pop_front();}if (qmin.front() == l){qmin.pop_front();}}return ans;}

以上都是题目中明确要求求窗口最大最小值的,下面这道题就不太明显了

加油站最佳出发点

题目描述

给你两个数组,gas和cost

其实gas[i]表示第i号加油站的油量,cost[i]表示从i号到i+1号加油站消耗的油量

车初始油量为0

返回一个bool类型,表示第i号加油站出发,车能不能完整绕过一圈,只能逆时针绕圈

例如:

gas=[1,1,3,1]
cost=[2,2,1,1]

图如下:


如果你从0号加油站出发,cost[0]是2,但gas[0]=1,车不能到1号加油站,所以ans[0]返回false

总体返回:[0,0,1,0]

思路求解:

我们在解题前,可以先进行一个加工

先将gas和cost每个位置对应数字相减,得到处理后的数组nums

for (int i = 0; i < n; i++)
{nums[i] = gas[i] - cost[i];
}

这样就能表示出从某一站出发,能不能到达它的下一站,如果结果为负数,则不能到达

我们可以求出前缀和,如果中途出现了负数,表示这一圈不能够完成

例如:从0开始的前缀和,表示从0出发,中途途径每个加油站的剩余油量
从1开始的前缀和,表示从1出发,以此类推

因为我们要绕一圈,所以我们应该处理出两倍的原数组大小(不从0开始出发?)

     int m=n<<1;for (int i = 0; i < n; i++){nums[i] = gas[i] - cost[i];nums[i + n] = gas[i] - cost[i];}for (int i = 1; i < m; i++){nums[i] += nums[i - 1];}

我们本题的窗口要求大小与原数组相同,我们可以这样处理我们的数组:

维持最小值窗口

显而易见,如果最小值不是负数,那么窗口中就没有负数了

在更新数组窗口时,我们记得把窗口中的值减去窗口左边界前面一个值,这样就才是正确的从l开始的前缀和

直接判断当前最小值是否小于0即可

代码即注释:

 vector<bool> GasStation(vector<int>& gas, vector<int>& cost){int n = gas.size();int m = n << 1;vector<bool>ans(n, false);int* nums = new int[m];for (int i = 0; i < n; i++){nums[i] = gas[i] - cost[i];nums[i + n] = gas[i] - cost[i];}for (int i = 1; i < m; i++){nums[i] += nums[i - 1];}deque<int>w;//初始化窗口for (int i = 0; i < n; i++){while (!w.empty() && nums[w.back()] >= nums[i]){w.pop_back();}w.push_back(i);}for (int offset = 0, i = 0, j = n; j < m; offset = nums[i++], j++){//offset表示窗口前面的数字,w始终维持窗口最小值//i左边界,j右边界if (nums[w.front()] - offset >= 0){ans[i] = true;}if (w.front() == i){w.pop_front();}while (!w.empty() && nums[w.back()] >= nums[j]){w.pop_back();}w.push_back(j);}delete[]nums;return ans;}

滑动窗口(最大最小值)的经典例题相关推荐

  1. 滑动窗口的最小值问题

    滑动窗口的最小值问题 滑动窗后的最小值问题.输入正整数k和一个长度为n的整数序列A1,A2,A3,-,AnA_1, A_2, A_3, - , A_n.定义f(i)f(i)表示从元素ii开始的连续kk ...

  2. queue emplace_c++ queue、deque、priority_queue/队列最大值/滑动窗口/top K

    本篇文章介绍c++中关于队列的stl相关方法及概念介绍,例举3个经典算法题 一.queue 队列,常用方法: size_type size() bool empty() void push(value ...

  3. 详解--单调队列 经典滑动窗口问题

    单调队列,即单调的队列.使用频率不高,但在有些程序中会有非同寻常的作用. 动态规划·单调队列的理解 做动态规划时常常会见到形如这样的转移方程: f[x] = max or min{g(k) | b[x ...

  4. 经典算法-并查集、快速排序、字典序算法、二分搜索、牛顿开方法、求质数(筛选法)、编辑距离、滑动窗口、异或求重、长除法

    目录 ​​​​​​​​​​​​​​ 并查集 快速排序 字典序算法 二分搜索 开根号-牛顿开方法 求质数 编辑距离 滑动窗口 异或求重 长除法 ​​​​​​​ 并查集 并查集用于解决相同元素集合动态连接 ...

  5. pandas计算滑动窗口中的最小值实战(Rolling Minimum in a Pandas Column):计算单数据列滑动窗口中的最小值、计算多数据列滑动窗口中的最小值

    pandas计算滑动窗口中的最小值实战(Rolling Minimum in a Pandas Column):计算单数据列滑动窗口中的最小值.计算多数据列滑动窗口中的最小值 目录

  6. 单调队列板子:求滑动窗口中最大值和最小值

    文章目录 题目分析 初始思路 单调队列优化的思路 代码1:数组模拟单调队列的代码 代码2:deque容器实现 能用到单调队列的情景比较有限: 1.典型的有滑动窗口的最值, 2.找到里它最近的比它大(小 ...

  7. LeetCode刷题:滑动窗口模板以及典型例题

    作者:fuxuemingzhu 链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/fen-xiang-hua- ...

  8. 求滑动窗口中的最大值和最小值

    滑动窗口: 一般使用双指针算法,左指针l和右指针r之间的空间称为窗口,由于指针是不断移动的,从而窗口也可以移动,称为滑动窗口. 滑动窗口的最值: 由于窗口是移动的,移动的过程中有新元素的加入也有旧元素 ...

  9. 三握,四挥,滑动窗口会了吗?面试TCP/IP经典问题总是忘?快来这里~

    目录 一.应用层 1.1 HTTP 1.2 XML 1.3 JSON 二.传输层 2.1 UDP协议 2.2 TCP协议 2.3 确认应答机制(TCP保证可靠性的核心机制) 2.4 超时重传 连接管理 ...

最新文章

  1. Gradle系列教程之依赖管理
  2. python操作yaml
  3. 调用Win32 API 之CreateCursor函数失败
  4. android震动服务能设置时长么,Android实现手机振动设置的方法
  5. android 遮罩 进度条,bootstrap创建带遮罩层的进度条
  6. 升级macOS Big Sur 无法开机/死机怎么办?
  7. python sklearn做文本分类
  8. iOS图形学(一):viewWillUnload和内存警告
  9. 新中新电子f200a驱动安装_【电子税务局】出口退税功能上线指引
  10. 【无线网络技术】星链计划(StarLink)
  11. OpenModelica中的可视化仿真
  12. 计算机动漫与游戏制作要画画基础吗,动漫制作要有绘画基础吗
  13. 2.1用户界面设计的八项黄金法则
  14. echarts上加横线标线_Echarts地图添加引导线效果(labelLine)
  15. Oracle heap 表的主键 dump 分析
  16. uptime 之一 /proc/uptime
  17. Stduino学习(二十六)水位传感器模块
  18. 腾讯财付通漏洞遭黑客利用
  19. js动态生成表格(原创)
  20. 光伏并网逆变器,F28335光伏并网逆变器

热门文章

  1. 利用cesium模拟台风移动路径——以利奇马台风为例
  2. 昨天,我的大学学习[3]--转载自:www.cstc.net.cn
  3. 计算机语言的发明者,Lisp语言发明者、“人工智能之父” John McCarthy与世长辞
  4. 不要让你的文件“失踪”,学会小米手机怎么备份
  5. Linux文件锁内核VFS层源码实现讲解
  6. u深度制作linux启动盘制作工具,u深度u盘启动盘制作工具 v3.1.15.316
  7. kubernetes 使用kubectl port-forward 访问应用
  8. “Red and Black(红黑瓷砖),ZOJ2165”的一种解法
  9. iframe内嵌标签
  10. docker-compose Seata+Nacos部署