POJ - 2823 Sliding Window (滑动窗口 单调队列模板题)

给定一个长度为n的数组和滑动窗口大小k,题目要求找出每次窗口移动时窗口内的最大值和最小值。解决方案是使用单调队列,队列头部保持当前窗口内的最大值或最小值。当新元素入队时,根据新元素与队尾元素的关系调整队列,确保队列单调性。出队时,若队头元素不在当前窗口内则继续出队,直到找到在窗口内的队头元素并输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Sliding Window

 题目链接:https://vjudge.net/problem/POJ-2823

An array of size n ≤ 10 6 is given to you. There is a sliding window of size kwhich 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

题目大意 :给一个长度为n的数列, 长度为k的滑动窗口的最小值和最大值

思路:滑动窗口就是一个数组的长度为k的一部分;
建立两个双端队列,该队列是有序队列,队头的元素分别为最小和最大;

进队列:如果当前元素比队尾元素大,或者队列为空,则直接进队;  如果当前元素比队尾元素小,则队尾元素出队,直至当前元素大于队尾元素或队列为空,然后当前元素入队;

 如果当前元素比队尾元素小,或者队列为空,则直接进队;     如果当前元素比队尾元素大,则队尾元素出队,直至当前元素小于队尾元素或队列为空,然后当前元素入队;                                                                                                                                  就是维护队列的单调性

出队列:取每个窗口对应的最小值的时候,要保证队头元素在窗口里面;
队头出列时,判断队头元素是否在窗口里面,如果在则直接输出;否则,则一直出队头元素,直至所出的队头元素在窗口里面,然后输出。 就是如果队头元素与当前入队的元素之间的距离大于等于k时 就不属于这个窗口的元素,就出队

一个单调队列,末端插入,弹出,首端只弹出,不插入。队首始终为最值。
如果新入队的元素与队头元素的距离>=滑动窗口的宽度,则队头元素出队列。

 

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1000005;
int a[N],ma[N],mi[N];
struct node
{
    int val,pos;
}maxq[N],minq[N];
int main()
{
    int n,k,maxh=0,maxt=0,minh=0,mint=0;
    scanf("%d%d",&n,&k);
    for(int i=0;i<k;i++)
    {
        scanf("%d",&a[i]);
        while(minh<mint&&minq[mint-1].val>=a[i]) mint--;
        minq[mint].val=a[i],minq[mint].pos=i;
        ++mint;
        while(maxh<maxt&&maxq[maxt-1].val<=a[i]) maxt--;
        maxq[maxt].val=a[i],maxq[maxt].pos=i;
        ++maxt;
    }
    int cnt=0;
    mi[cnt]=minq[minh].val;
    ma[cnt]=maxq[maxh].val;
    ++cnt;
    for(int i=k;i<n;i++)
    {
        scanf("%d",&a[i]);
        while(minh<mint&&i-minq[minh].pos>=k) minh++;
        while(maxh<maxt&&i-maxq[maxh].pos>=k) maxh++;

        while(minh<mint&&minq[mint-1].val>=a[i]) mint--;
        minq[mint].val=a[i],minq[mint].pos=i;
        ++mint;
        while(maxh<maxt&&maxq[maxt-1].val<=a[i]) maxt--;
        maxq[maxt].val=a[i],maxq[maxt].pos=i;
        ++maxt;
        mi[cnt]=minq[minh].val;
        ma[cnt]=maxq[maxh].val;
        ++cnt;
    }

    printf("%d",mi[0]);
    for(int i=1;i<cnt;i++)
        printf(" %d",mi[i]);
    printf("\n%d",ma[0]);
    for(int i=1;i<cnt;i++)
        printf(" %d",ma[i]);
    printf("\n");
    return 0;
}

 

代码2:(下标入队)

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1000005;
int a[N],qi[N],qa[N],mi[N],ma[N];
int main()
{
    int n,m,la=0,ra=0,li=0,ri=0;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d",&a[i]);
        while(li<ri&&a[qi[ri-1]]>=a[i]) --ri;
        qi[ri++]=i;
        while(la<ra&&a[qa[ra-1]]<=a[i]) --ra;
        qa[ra++]=i;
    }
    int cnt=0;
    mi[cnt]=a[qi[li]];
    ma[cnt++]=a[qa[la]];
    for(int i=m;i<n;i++)
    {
        scanf("%d",&a[i]);
        while(li<ri&&i-qi[li]>=m) li++;
        while(la<ra&&i-qa[la]>=m) la++;
        while(li<ri&&a[qi[ri-1]]>=a[i]) --ri;
        qi[ri++]=i;
        while(la<ra&&a[qa[ra-1]]<=a[i]) --ra;
        qa[ra++]=i;
        mi[cnt]=a[qi[li]];
        ma[cnt++]=a[qa[la]];
    }
    for(int i=0;i<cnt;i++)
        printf("%d%c",mi[i],i==cnt-1?'\n':' ');
    for(int i=0;i<cnt;i++)
        printf("%d%c",ma[i],i==cnt-1?'\n':' ');
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值