POJ-2823 Sliding Window(单调队列)

版权声明:转载请说明出处:https://blog.csdn.net/hanyanwei123 https://blog.csdn.net/hanyanwei123/article/details/81346963
Sliding Window
An array of size n ≤ 10 6 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 position Minimum value Maximum value
[1  3  -1] -3  5  3  6  7  -1 3
 1 [3  -1  -3] 5  3  6  7  -3 3
 1  3 [-1  -3  5] 3  6  7  -3 5
 1  3  -1 [-3  5  3] 6  7  -3 5
 1  3  -1  -3 [5  3  6] 7  3 6
 1  3  -1  -3  5 [3  6  7] 3 7

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

题意:给定n,k.; n个数字,k为间隔,以k为单位向右滑动,每次滑动一个,找出其中最小值和最大值。
最小值和最大值数组有n+1-k个
关键在于处理最值,例如找最小值,设A[i],Q[i],P[i],Min[i]分别为存储数据数组,单调队列,记录进入队列元素下标的数组,和答案数组;
从第k个元素开始才有第一个答案,所有先把k-1个元素处理下,处理规则;既然是找区间最小值,从左向右入队列,建立递增队列,若遇到比队列尾部小的数,从尾部向前扫描,代替最后一个大于它的数,并记录下标,为了保证向前代替在合理区域,要将不在单位区间的元素去掉,head++;(从队尾插入新元素的时候可能要删除队尾的一些元素,具体说来就是,找到第一个大于(在所关注指标下)新元素的元素,删除其后所有元素,并将新元素插于其后。因为所有被删除的元素都比新元素要小

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1000000+10;

int A[maxn];//存储数据
int Q[maxn];//队列
int p[maxn];//记录进入队列元素的下标
int Min[maxn];//最小答案数组
int Max[maxn];//区间最大值

int n,k;

//找最小值
void getmin()
{
    //cout << "jinlaile1"<< endl;
    //先存入前k-1个
    int head=1,tail=0;//队列两个位置指针

    for(int i=0;i<k-1;i++)
    {
        //队列非空tail>=head
        //从0开始存
        while(head<=tail&&Q[tail]>=A[i])
            --tail;
        //队尾元素大于将要入队列的数,则--,依次往前查询
        Q[++tail]=A[i];//代替比A[i]的,左侧最多只有两个,
        p[tail]=i;//记录下标;tail=1,开始
    }

    for(int i=k-1;i<n;i++)
    {

        while(head<=tail&&Q[tail]>=A[i])
            --tail;
        Q[++tail]=A[i];
        p[tail]=i;
        while(p[head]<i-k+1)
            head++;
        Min[i-k+1]=Q[head];
    }


}
void getmax()
{

    //先存入前k-1个
    int head=1,tail=0;//队列两个位置指针

    for(int i=0;i<k-1;i++)
    {
        //队列非空tail>=head
        //从0开始存
        while(head<=tail&&Q[tail]<=A[i])
            --tail;
        //队尾元素大于将要入队列的数,则--,依次往前查询
        Q[++tail]=A[i];//代替比A[i]的,左侧最多只有两个,
        p[tail]=i;//记录下标;
    }
    for(int i=k-1;i<n;i++)
    {
        while(head<=tail&&Q[tail]<=A[i])
            --tail;
        Q[++tail]=A[i];
        p[tail]=i;
        while(p[head]<i-k+1)
            head++;
        Max[i-k+1]=Q[head];
    }

}
void output()
{
        for(int i=0;i<n+1-k;i++)
            printf("%d ",Min[i]);
        cout << endl;
        for(int i=0;i<n+1-k;i++)
            printf("%d ",Max[i]);
}

int main()
{
    scanf("%d %d",&n,&k);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&A[i]);
    }
    getmin();
    getmax();
    output();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hanyanwei123/article/details/81346963