POJ2823
题目:给出n个数(n<=1000000)和k,从左到右依次求每k个数字的最大,最小值
红果果的单调队列,算是一道学习单调队列的好题了。
单调队列,名字听起来挺高大上,其实很简单。
同样用到一个普通的队列,一个头指针和一个尾指针,队列用结构体定义,包含两个成员,该元素的值和改元素在原数组中的下标。
单调队列,顾名思义,就是说这个队列里的元素是单调的,递增或递减。查询最小值是O(1),总的复杂度是O(N)这里以单调递增为例,可以求出每个k区间内的最小值。单调队列里面元素是递增的,对于每一个新入队的元素,先从队尾开始向前找第一个小于这个要入队的元素,然后把找到的这个元素后面的所有队员全部从队尾出队(将尾指针移到所找到的元素的后面一个即可),这样这个元素就入队了。对于每个区间,队头元素就是该区间的最小值。
举个单调队列的例子。
8
1 3 -1 -3 5 3 6 7
一开始,队列为空,
1 入队
3 入队,从队尾找第一个小于3的元素,即 1 ,接着将 3放到1后
-1 入队 1、3都大于 -1 所以1和3 都出队,-1 则排到了队头
-3 入队 -3 小于 -1,-1出队,-3为队头元素
5 入队,5大于-3 5排到-3后
3 入队 5出队,3排到-3后,这时队列只有两个元素 -3 和3
6 入队,3小于6 则6排到队尾3的后面
7 入队 排到队尾
其实这个东西很简单,具体看看程序想一想就理解。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 const int maxn = 1000005; 6 struct node 7 { 8 int value; 9 int index; 10 }que[maxn]; 11 int a[maxn]; 12 int front,rear; 13 int main() 14 { 15 //freopen("in.txt","r",stdin); 16 int n,k; 17 while(cin>>n>>k) 18 { 19 for(int i = 1;i<=n;++i)scanf("%d",a+i); 20 front = 1;rear = 0; 21 //求最小值 22 for(int i = 1;i<k;++i) 23 { 24 //在队列非空,情况下,从队尾找小于a[i]的第一个位置 25 while(front<=rear && que[rear].value>=a[i])rear--; 26 que[++rear].value = a[i]; 27 que[rear].index = i; 28 } 29 for(int i = k;i<=n;++i) 30 { //删除队尾不需要的元素,将第k个元素入队 31 while(front<=rear && que[rear].value>=a[i])rear--; 32 que[++rear].value = a[i]; 33 que[rear].index = i; 34 //维护队列的长度不超过k 35 if(que[front].index<=i-k)front++; 36 printf("%d ",que[front].value); 37 } 38 printf("\n"); 39 //求最大值 40 front = 1;rear = 0; 41 for(int i = 1;i<k;++i) 42 { 43 while(front<=rear && que[rear].value<=a[i])rear--; 44 que[++rear].value = a[i]; 45 que[rear].index = i; 46 } 47 for(int i = k;i<=n;++i) 48 { 49 while(front<=rear && que[rear].value<=a[i])rear--; 50 que[++rear].value = a[i]; 51 que[rear].index = i; 52 if(que[front].index<=i-k)front++; 53 printf("%d ",que[front].value); 54 } 55 56 } 57 return 0; 58 }
弱者究竟为何而战?!