滑动窗口(最大最小值)的经典例题
滑动窗口简单概念
滑动窗口是我们假想出的一种数据结构,我们在这篇文章实现的窗口,能较快速的求区间最大最小值
在一些区间不回退的题目中运行效率也十分优秀
设窗口的左边界为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;}
滑动窗口(最大最小值)的经典例题相关推荐
- 滑动窗口的最小值问题
滑动窗口的最小值问题 滑动窗后的最小值问题.输入正整数k和一个长度为n的整数序列A1,A2,A3,-,AnA_1, A_2, A_3, - , A_n.定义f(i)f(i)表示从元素ii开始的连续kk ...
- queue emplace_c++ queue、deque、priority_queue/队列最大值/滑动窗口/top K
本篇文章介绍c++中关于队列的stl相关方法及概念介绍,例举3个经典算法题 一.queue 队列,常用方法: size_type size() bool empty() void push(value ...
- 详解--单调队列 经典滑动窗口问题
单调队列,即单调的队列.使用频率不高,但在有些程序中会有非同寻常的作用. 动态规划·单调队列的理解 做动态规划时常常会见到形如这样的转移方程: f[x] = max or min{g(k) | b[x ...
- 经典算法-并查集、快速排序、字典序算法、二分搜索、牛顿开方法、求质数(筛选法)、编辑距离、滑动窗口、异或求重、长除法
目录 并查集 快速排序 字典序算法 二分搜索 开根号-牛顿开方法 求质数 编辑距离 滑动窗口 异或求重 长除法 并查集 并查集用于解决相同元素集合动态连接 ...
- pandas计算滑动窗口中的最小值实战(Rolling Minimum in a Pandas Column):计算单数据列滑动窗口中的最小值、计算多数据列滑动窗口中的最小值
pandas计算滑动窗口中的最小值实战(Rolling Minimum in a Pandas Column):计算单数据列滑动窗口中的最小值.计算多数据列滑动窗口中的最小值 目录
- 单调队列板子:求滑动窗口中最大值和最小值
文章目录 题目分析 初始思路 单调队列优化的思路 代码1:数组模拟单调队列的代码 代码2:deque容器实现 能用到单调队列的情景比较有限: 1.典型的有滑动窗口的最值, 2.找到里它最近的比它大(小 ...
- LeetCode刷题:滑动窗口模板以及典型例题
作者:fuxuemingzhu 链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/fen-xiang-hua- ...
- 求滑动窗口中的最大值和最小值
滑动窗口: 一般使用双指针算法,左指针l和右指针r之间的空间称为窗口,由于指针是不断移动的,从而窗口也可以移动,称为滑动窗口. 滑动窗口的最值: 由于窗口是移动的,移动的过程中有新元素的加入也有旧元素 ...
- 三握,四挥,滑动窗口会了吗?面试TCP/IP经典问题总是忘?快来这里~
目录 一.应用层 1.1 HTTP 1.2 XML 1.3 JSON 二.传输层 2.1 UDP协议 2.2 TCP协议 2.3 确认应答机制(TCP保证可靠性的核心机制) 2.4 超时重传 连接管理 ...
最新文章
- Gradle系列教程之依赖管理
- python操作yaml
- 调用Win32 API 之CreateCursor函数失败
- android震动服务能设置时长么,Android实现手机振动设置的方法
- android 遮罩 进度条,bootstrap创建带遮罩层的进度条
- 升级macOS Big Sur 无法开机/死机怎么办?
- python sklearn做文本分类
- iOS图形学(一):viewWillUnload和内存警告
- 新中新电子f200a驱动安装_【电子税务局】出口退税功能上线指引
- 【无线网络技术】星链计划(StarLink)
- OpenModelica中的可视化仿真
- 计算机动漫与游戏制作要画画基础吗,动漫制作要有绘画基础吗
- 2.1用户界面设计的八项黄金法则
- echarts上加横线标线_Echarts地图添加引导线效果(labelLine)
- Oracle heap 表的主键 dump 分析
- uptime 之一 /proc/uptime
- Stduino学习(二十六)水位传感器模块
- 腾讯财付通漏洞遭黑客利用
- js动态生成表格(原创)
- 光伏并网逆变器,F28335光伏并网逆变器
热门文章
- 利用cesium模拟台风移动路径——以利奇马台风为例
- 昨天,我的大学学习[3]--转载自:www.cstc.net.cn
- 计算机语言的发明者,Lisp语言发明者、“人工智能之父” John McCarthy与世长辞
- 不要让你的文件“失踪”,学会小米手机怎么备份
- Linux文件锁内核VFS层源码实现讲解
- u深度制作linux启动盘制作工具,u深度u盘启动盘制作工具 v3.1.15.316
- kubernetes 使用kubectl port-forward 访问应用
- “Red and Black(红黑瓷砖),ZOJ2165”的一种解法
- iframe内嵌标签
- docker-compose Seata+Nacos部署