单调队列的特点,一个是严格单调性(不是非递增或者非递减),这样方便求区间最值;另外一个就是队头队尾都可以出队,但是只有队尾能入队,这个特点是为了保证队列内没有区间外的元素。常见应用,区间求最值,还有动态规划的优化处理。
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; }