poj 2823 Sliding Window(单调队列)

Description

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

大致题意:给你一个数组a[],然后让你求这个数组中连续k个元素的最大值和最小值,按顺序分两行输出。

思路:用单调队列来写。
对于单调队列,我们这样子来定义:
1、维护区间最值
2、去除冗杂状态 ,区间中的两个元素a[i],a[j](假设现在再求最小值) 若 j>i且a[j]<=a[i] ,a[j]比a[i]还小而且还在后面(目前a[j]留在队列肯定比a[i]有用,所以你就可以把a[i]出队,即tail–)
3、保持队列单调,最小值是单调递增序列,最小值反之
4、最优选择在队首

大致过程:
1、维护队首(head++)
2、在队尾插入(每插入一个就要从队尾开始往前去除冗杂状态,tail–)

代码如下

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<vector>
#include<cstring>
#define LL long long int 
using namespace std;
const int N=1e6+5;
struct node
{
    int num;
    int cost;
    node(int _num=0,int _cost=0):num(_num),cost(_cost){}
}q[N];
int n,k;
int a[N];
int Max[N];
int Min[N];

void getmin()
{
    int head=1,tail=1;
    int i;
    for(i=1;i<=k-1;i++)
    {
        while(head<tail&&a[i]<=q[tail-1].cost) tail--;
        q[tail++]=node(i,a[i]);
    }
    for(;i<=n;i++)
    {
        while(head<tail&&a[i]<=q[tail-1].cost) tail--;
        q[tail++]=node(i,a[i]);

        while(q[head].num<i-k+1) head++;
        Min[i-k+1]=q[head].cost;
    }
}

void getmax()
{
    int head=1,tail=1;
    int i;
    for(i=1;i<=k-1;i++)
    {
        while(head<tail&&a[i]>=q[tail-1].cost) tail--;
        q[tail++]=node(i,a[i]);
    }
    for(;i<=n;i++)
    {
        while(head<tail&&a[i]>=q[tail-1].cost) tail--;
        q[tail++]=node(i,a[i]);

        while(q[head].num<i-k+1) head++;
        Max[i-k+1]=q[head].cost;
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]); 
    getmin();
    getmax();

    for(int i=1;i<=n-k+1;i++)
    {
        if(i==1)
        printf("%d",Min[i]);
        else 
        printf(" %d",Min[i]);
    }
    printf("\n");
    for(int i=1;i<=n-k+1;i++) 
    {
        if(i==1)
        printf("%d",Max[i]);
        else 
        printf(" %d",Max[i]);
    }
    printf("\n");

    return 0;
}

(不过用G++或GCC交会超时。。。需要用C++交,之前用了二分优化进队时的操作也没什么太好的效果,。,。目前就先这样好了,改天再回来优化。。。。)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值