单调队列就是队列中的元素是单调递增或递减的。比如把 5 2 3 1 4 入队:
减:、、、、、、、、、、、增:
5 、、、、、、、、、、、、5
5 2 、、、、、、、、、、、2
5 3 、、、、、、、、、、、2 3
5 3 1、、、、、、、、 、、1
5 4 、、、、、、、、、、、1 4
这个还是好理解的,但是,我们得会用单调队列这一特性去解决题目,抽象出题目中有类似的操作。
题意:
给三个数 n,x,y;
接下来n个数num[1~n];
求满足这个条件的最长区间长度:区间内最大值与最小值之差在 x~y之间。
方法:
单调队列记录下标。
由一个递增,一个递减的单调队列,可得前面的某个位置~当前位置的最大差值def=num[q1.front()]-num[q2.front()];
如果def>y,则让下标靠前的那个出队列。
上代码,看注释:
#include <stdio.h>
#include <iostream>
#include <deque>
using namespace std;
inline int fmax(int a,int b){return a>b?a:b;}
int main()
{
int n,x,y;
int num[100005];
while(scanf("%d %d %d",&n,&x,&y)!=EOF)
{
for(int i=1;i<=n;++i)
scanf("%d",&num[i]);
deque<int >q1,q2; //两个队列,q1.front()存最大值,q2.front()存最小值
int max=0,last=0; //last记录最后弹出元素的位置
for(int i=1;i<=n;i++){
while(!q1.empty() && num[i]>num[q1.back()]) q1.pop_back();//维护队列单调型
while(!q2.empty() && num[i]<num[q2.back()]) q2.pop_back();
q1.push_back(i);
q2.push_back(i);
//若对不空,且def>y,让下标靠前的出队。
while(!q1.empty() && !q2.empty() && num[q1.front()]-num[q2.front()]>y){
if(q1.front()>q2.front())
{
last=q2.front();
q2.pop_front();
}
else if(q1.front()<q2.front())
{
last=q1.front();
q1.pop_front();
}
else if(q1.front()>q2.front())
{
last=q2.front();
q1.pop_front();
q2.pop_front();
}
}
if(!q1.empty() && !q1.empty() && num[q1.front()]-num[q2.front()]>=x)
max=fmax(max,i-last);//若当前区间的def满足>=x,取区间最大长度
}
printf("%d\n",max);
}
return 0;
}