POJ-2823-Sliding Window (单调队列)

原题链接
http://poj.org/problem?id=2823
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.
在这里插入图片描述
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个窗口,从第一个一直滑动到最后一个,美妙滑动一次,每次滑动向后一个,每滑动一次就输出窗口里的数列的最小值和最大值。具体格式见样例。
题解:
这道题目可以利用单调队列,利用数组记录当前窗口的最大(小)值。
以找最小值举例说明:
滑动窗口时,插入元素:删除掉所有的所有比插入元素大的数值,代码里其实就是将队列q的右端点向左移,直到有比 插入元素小的时候插入。
如何实现窗口移动,并且保持队列单调呢?
如果队首元素的位置小于窗口的左界,则删除,其他的不用管,因为最终输出的时队首元素,在队首其后的元素对其不产生影响,并且如果在之后的移动中,之前未删除的不在窗口的元素也会被删除的。
(更多细节见代码,请读者细细体会)

注意:这道题目耗时比较长,用cin,cout输入输出会超时

附上AC代码:

#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN=1e6+5;
int a[MAXN],q[MAXN],n,k;
void workmin()
{
    int l=1,r=0,i=0;
    for(; i<k-1; i++)//初始化队前k-1个元素
    {
        while(l<=r&&a[q[r]]>a[i]) r--;//当左端点小于右端点并且删除掉比插入元素大的队尾元素
        q[++r]=i;//插入输入元素
    }
    for(; i<n; i++)//窗口移动
    {
        if(q[l]<=i-k) l++;//删除不在窗口的队首元素
        while(l<=r&&a[q[r]]>a[i]) r--;//含义同上,实现窗口移动
        q[++r]=i;
        printf("%d ",a[q[l]]);//输出最小值
    }
    printf("\n");
}
void workmax()
{
    int l=1,r=0,i=0;
    for(; i<k-1; i++)//初始化队的前k-1个元素
    {
        while(l<=r&&a[q[r]]<a[i]) r--;//左端点小于右端点,并且删除队尾比插入元素小的元素实现单调递减
        q[++r]=i;//插入元素
    }
    for(; i<n; i++)
    {
        if(q[l]<=i-k) l++;//不在窗口内的都删除
        while(l<=r&&a[q[r]]<a[i]) r--;
        q[++r]=i;
        printf("%d ",a[q[l]]);//输出最大值printf
    }
    printf("\n");
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(int i=0; i<n; i++)
            scanf("%d",a+i);
        workmin();
        workmax();
    }
    return 0;
}

欢迎评论!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值