单调队列的特点,一个是严格单调性(不是非递增或者非递减),这样方便求区间最值;另外一个就是队头队尾都可以出队,但是只有队尾能入队,这个特点是为了保证队列内没有区间外的元素。常见应用,区间求最值,还有动态规划的优化处理。
POJ2823 Sliding Windo,就是典型的求区间最值问题,单调队列可解
CODE:
#include<stdio.h>
//const int N = 1000001;
#define N 1000001
int num[N],que[N];
int main()
{
int i,n,k;
int head,tail;
scanf("%d%d",&n,&k);
for(i=0;i<n;i++){
scanf("%d",&num[i]);
}
head=0,tail=0;
que[0]=0;
for(i=0;i<k;i++){//前3个特殊处理,避免重复输出
//队列que中保存的是数组元素下标;因为要找的是区间最小值,所以维护队列的严格递增,也就是说,即将操作的
//元素必须大于队尾元素才能入队,否则队尾元素一直出队,直到队尾元素小于即将操作的数,或者队列为空
while(num[ que[tail] ]>=num[i] && head<=tail)
tail--;
que[++tail] = i;
}
printf("%d ",num[ que[head] ]);
for(;i<n;i++){
while(num[ que[tail] ]>=num[i] && head<=tail)
tail--;
que[++tail]=i;
while(i-que[head] >= k)//距离差距超过k的话,队头出队,直到队列长度不超过k
head++;
if(i!=n-1)
printf("%d ",num[ que[head] ]);
}
printf("%d\n",num[ que[head] ]);
/*找的是区间最大值,所以维护的是队列的严格递减,其余跟上面一样*/
head=0,tail=0;
que[0]=0;
for(i=0;i<k;i++){
while(num[ que[tail] ]<=num[i] && head<=tail)
tail--;
que[++tail] = i;
}
printf("%d ",num[ que[head] ]);
for(;i<n;i++){
while(num[ que[tail] ]<=num[i] && head<=tail)
tail--;
que[++tail]=i;
while(i-que[head] >= k)//距离差距超过k的话,队头出队,直到队列长度不超过k
head++;
if(i!=n-1)
printf("%d ",num[ que[head] ]);
}
printf("%d\n",num[ que[head] ]);
return 0;
}