poj Sliding Window

来源:互联网 发布:java环境变量设置脚本 编辑:程序博客网 时间:2024/05/16 03:57
Sliding Window
Time Limit: 12000MS Memory Limit: 65536KTotal Submissions: 50163 Accepted: 14456Case 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 31 3 -1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 33 3 5 5 6 7

Source

POJ Monthly--2006.04.28, Ikki
题目大意

给定你n个数ai~an一个确定长度的区间,让你求出每个区间内的最大值,并按照顺序输出

输入

   Nk

   A1~an

输出

  每个区间内的最大值

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int queue[1000003];
int n,k,i,j,a[1000003];
int head1,tail1,head2,tail2;
inline bool scan_d(int &num)    //快速读入
{  
    char in;bool IsN=false;  
    in=getchar();  
    if(in==EOF)  
        return false;  
    while(in!='-'&&(in<'0'||in>'9')) in=getchar();  
    if(in=='-')   { IsN=true;num=0;}  
    else num=in-'0';  
    while(in=getchar(),in>='0'&&in<='9')  
    {  
        num*=10,num+=in-'0';  
    }  
    if(IsN)  
        num=-num;  
    return true;  
}  
int main()
{
scanf("%d%d\n",&n,&k);
for (i=1;i<=n;i++)
scan_d(a[i]);
if (k==1)
{
for (i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n");
for (i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}
tail1=1;  queue[1]=1; head1=1;
for (i=2;i<=n;i++)
{
while (queue[head1]<i-k+1&&head1<=tail1)
head1++;
while (a[queue[tail1]]>a[i]&&tail1>=head1)
tail1--;
tail1++; queue[tail1]=i;
if (i>=k)
printf("%d ",a[queue[head1]]);
}
printf("\n");
memset(queue,0,sizeof(queue));
tail1=1;  queue[1]=1; head1=1;
for (i=2;i<=n;i++)
{
while (queue[head1]<i-k+1&&head1<=tail1)
head1++;
while (a[queue[tail1]]<a[i]&&tail1>=head1)
tail1--;
tail1++;  queue[tail1]=i;
if (i>=k)
printf("%d ",a[queue[head1]]);
}
}

//这题首先想到的是线段树,但是每次都查询时间复杂度太高。

于是想到单调队列,所谓单调队列就是保持单调性的队列,单调队列又称双端队列,即既可以从尾出队,又可以从头出队。以此题为例,我们保证队首元素最大(或最小),因为有范围限制,那么如果队列的头元素的下标已经超出了(i-k+1),那么我们就可以出队。然后把当前元素从尾端入队,只要队尾元素比当前元素小(或大),那么队尾元素出队,因为我们要维护的是最值,所以队尾元素直接出队即可,不会影响最终结果。有一点需要特别注意,那就是队首与队尾的范围,最少的情况是队中只有一个元素,即head==tail.


0 0