单调队列是一种特殊的队列,可以在队头和队尾两边操作,并且始终维护队列的单调性。这种单调性分为两种:元素值严格单调, 元素下标严格单调
滑动窗口最大值
这是一道经典的单调队列问题,因为滑动窗口一直都是动态变化,并且要求出窗口中的最大值,那么我们可以通过建立单调递减的队列,队头即为最大值,那么我们在每次滑动窗口的时候,判断队头元素是否已经划出窗口来判断最大值是否合法,如果合法则为当前窗口的最大值,如果不合法那么队头出列,因此我们每次入队的是元素的下标。每当滑动窗口往前移动一个单位就是要新进来一个数字,那么我们要判断新进来的数字是否要替换队列中的元素,因为要维护单调递减的队列,那么如果新的数字要大于队尾就要让队尾的元素删除并且添加新进来的元素,以此来维护单调队列
public class 单调队列优化 {
public static void main(String[] args) {
Scanner sr = new Scanner(System.in);
int m = sr.nextInt();//输入数组长度
int f[] = new int[m+1];//目标数组
for(int i=1;i<=m;++i){
f[i] = sr.nextInt();
}
int k = sr.nextInt();//窗口长度
int dl_down[] = new int[k+1];//减序队列数组,找最大值
int Min[] = new int[m+1];
int Max[] = new int[m+1];
int st = 1,ed = 1;//定义队列的两个指针
//初始化值
dl_down[1] = 1;
Min[1] = f[dl_down[1]];
ed++;
for(int i=2;i<=m;++i) {//遍历数组
while(st<ed) {//st==ed空队列,第i个数小于队尾就将队尾删除,ed--
if(f[i] >= f[dl_down[ed-1]])ed--;
else {
break;
}
}
dl_down[ed++] = i;//将i存入
//更新min,判断对头是否过时
if(dl_down[st]<i-k+1)st++;
Min[i] = f[dl_down[st]];
}
for(int i=k;i<=m;++i) {
System.out.print(Min[i]);
}
}
}