首页 > 代码库 > ACM-单调队列之Sliding Window——poj2823

ACM-单调队列之Sliding Window——poj2823

Sliding Window
Time Limit: 12000MS Memory Limit: 65536K
Total Submissions: 36326 Accepted: 10762
Case Time Limit: 5000MS

Description

An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example: 
The array is [1 3 -1 -3 5 3 6 7], and k is 3.
Window positionMinimum valueMaximum value
[1  3  -1] -3  5  3  6  7 -13
 1 [3  -1  -3] 5  3  6  7 -33
 1  3 [-1  -3  5] 3  6  7 -35
 1  3  -1 [-3  5  3] 6  7 -35
 1  3  -1  -3 [5  3  6] 7 36
 1  3  -1  -3  5 [3  6  7]37

Your task is to determine the maximum and minimum values in the sliding window at each position. 

Input

The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line. 

Output

There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values. 

Sample Input

8 3
1 3 -1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 3
3 3 5 5 6 7
题目:http://poj.org/problem?id=2823
之前在讨论 hdu魔板 这道题的时候,有人提到了O(1)队列,于是 度娘搜索到了这道题。做一下咯~
①什么是O(1)队列?
O(1)队列又称单调队列,顾名思义,就是队列中的元素是单调的。
要么单调递增,要么单调递减。
那么,构建单调队列有什么用呢?
我们维护一个队列后,我们查找当前队列内元素最大值/最小值  就可以是O(1)的速度了。
或许有人(比如我刚开始就想过)问:用优先队列,设置一下优先级不就可以了。
但是,要知道STL的东东,都挺耗时间的,尤其是 优先队列。
一般用单调队列做的题,对时间要求比较高,所以优先队列显然不能满足要求。
②单调队列如何维护
以单调递增队列来举例:

1、如果队列的长度一定,先判断队首元素是否在规定范围内,如果超范围则增长队首。

2、每次加入元素时和队尾比较,如果当前元素小于队尾且队列非空,则减小尾指针,队尾元素依次出队,直到满足队列的调性为止

要特别注意头指针和尾指针的应用。

参考资料:http://www.cnblogs.com/neverforget/archive/2011/10/13/ll.html

http://xuyemin520.is-programmer.com/posts/25964

And 这道题就可以解决了。

/**************************************
***************************************
*        Author:Tree                  *
*From :http://blog.csdn.net/lttree    *
* Title : Sliding Window              *
*Source: poj 2823                     *
* Hint  : 单调队列                   *
***************************************
**************************************/
#include <stdio.h>
#define MAX 1000001
int n,k;
int pre1,pre2,lst1,lst2,len_max,len_min;    // 两个队列的头指针与尾指针,最大值的下标,最小值的下表
int num[MAX],Increase[MAX],Decrease[MAX],Max[MAX],Min[MAX];      // Num存数据,递增与递减队列,最大值,最小值的数组。
// 递增序列的压入操作
void in_max(int i)
{
    while( pre1<=lst1 && num[ Increase[lst1] ]<num[i] )
        --lst1;
    Increase[++lst1]=i;

    // 如果大于等于k个数,就需要向最大值数组赋值
    if( i>=k )
    {
        if(Increase[pre1]<=i-k)
            pre1++;
        Max[len_max++]=num[ Increase[pre1] ];
    }
}
// 递减序列的压入操作
void in_min(int i)
{
    while( pre2<=lst2 && num[ Decrease[lst2] ]>num[i] )
        --lst2;
    Decrease[++lst2]=i;

    // 如果大于等于k个数,就需要向最小值数组赋值
    if( i>=k )
    {
        if(Decrease[pre2]<=i-k)
            pre2++;
        Min[len_min++]=num[ Decrease[pre2] ];
    }
}
int main()
{
    int i;
    while( ~scanf("%d%d",&n,&k) )
    {
        // 初始化
        pre1=pre2=len_max=len_min=0;
        lst1=lst2=-1;

        // 读入数据
        for(i=1;i<=n;++i)
        {
            scanf("%d",&num[i]);
            in_max(i);
            in_min(i);
        }

        // 输出数据
        for( i=0;i<len_min-1;++i )
            printf("%d ",Min[i]);
        printf("%d\n",Min[len_min-1]);
        for( i=0;i<len_max-1;++i )
            printf("%d ",Max[i]);
        printf("%d\n",Max[len_max-1]);
    }
    return 0;
}