POJ 2823 Sliding Window/单调队列

我的心愿是世界和平!

题目描述:第一行给数字n,k,接下来一行给出n个数字,在每k个数字中找到他的最大最小值。输出有两行,分别有n-k+1个数,第一行为最小值,第二行为最大值。注意:n的范围为1e6,暴力会超时。
思路:维护一个单调递减的队列,例如 3 2 5 4,3为首,直接入队列(3),2比3小,入队列(3 2),5比2大,2出队列,5比3大,3出队列(5),4比5小,入队列(5 4),这样,队首即为当前数据的最大值,在此题中,需要记录队列中数据的位置,若已经超出k个,则队首出队列。单增队列同上。
建议使用双端队列,若用数组模拟双端队列,需注意下标的控制。
样例:8 3
    1 3 -1 -3 5 3 6 7
   // -1 -3 -3 -3 3 3
   //3 3 5 5 6 7
    3 2
    3 2 1
   //2 1
   //3 2
    8 3
    -1 2 3 4 5 -9 6 2
   //-1 2 3 -9 -9 -9
   //3 4 5 5 6 6

双端队列

#include<iostream>
#include<queue>
#include<cstdio>
#define sf scanf
const int M=1e6+10;
using namespace std;
struct node
{
    int x;
    int y;
} s[M+50];
void Min_Max(int n,int k)
{
    int i;
    deque<node>q;
    for(i=1; i<=k; i++)
    {
        if(q.empty()||s[i].x>=q.back().x)
            q.push_back(s[i]);
        else
        {
            while(s[i].x<q.back().x)
            {
                q.pop_back();
                if(q.empty())
                    break;
            }
            q.push_back(s[i]);
        }
    }
    cout<<q.front().x;
    for(i=k+1; i<=n; i++)
    {
        if(q.empty()||s[i].x>=q.back().x)
            q.push_back(s[i]);
        else
        {
            while(s[i].x<q.back().x)
            {
                q.pop_back();
                if(q.empty())
                    break;
            }
            q.push_back(s[i]);
        }
        while(q.back().y-q.front().y>=k)
            q.pop_front();
        cout<<" "<<q.front().x;
    }
    cout<<endl;
}
void Max_Min(int n,int k)
{
    int i;
    deque<node>q;
    for(i=1; i<=k; i++)
    {
        if(q.empty()||s[i].x<=q.back().x)
            q.push_back(s[i]);
        else
        {
            while(s[i].x>q.back().x)
            {
                q.pop_back();
                if(q.empty())
                    break;
            }
            q.push_back(s[i]);
        }
    }
    cout<<q.front().x;
    for(i=k+1; i<=n; i++)
    {
        if(q.empty()||s[i].x<=q.back().x)
            q.push_back(s[i]);
        else
        {
            while(s[i].x>q.back().x)
            {
                q.pop_back();
                if(q.empty())
                    break;
            }
            q.push_back(s[i]);
        }
        while(q.back().y-q.front().y>=k)
            q.pop_front();
        cout<<" "<<q.front().x;
    }
}
int main()
{
    int n,k,i,j;
    sf("%d%d",&n,&k);
    for(i=1; i<=n; i++)
    {
        sf("%d",&s[i].x);
        s[i].y=i;
    }
    Min_Max(n,k);
    Max_Min(n,k);
}

数组模拟

#include<stdio.h>
struct point
{
    int value;
    int num;
} max[1000001],min[1000001];
int s[1000001],ss[1000001];
int main()
{
    int t,i,j,m,n,k,p,maxp=0,minp=0,maxq=0,minq=0;
    scanf("%d%d",&n,&k);
    if(k==1)
    {
        for(i=0; i<n; i++)
        {
            scanf("%d",&m);
            s[i]=m;
            ss[i]=m;
        }
        t=n;
    }
    else
    {
        scanf("%d",&m);
        max[0].value=min[0].value=m;
        max[0].num=min[0].num=0;
        p=0;
        for(i=1; i<k-1; i++)
        {
            scanf("%d",&m);
            if(m<=max[maxq].value)
            {
                max[++maxq].value=m;
                max[maxq].num=i;
            }
            else
            {
                while(maxq>=maxp&&m>max[maxq].value)
                    maxq--;
                max[++maxq].value=m;
                max[maxq].num=i;
            }
            if(m>=min[minq].value)
            {
                min[++minq].value=m;
                min[minq].num=i;
            }
            else
            {
                while(minq>=maxp&&m<min[minq].value)
                    minq--;
                min[++minq].value=m;
                min[minq].num=i;
            }
        }
        t=0;
        for(i=k-1; i<n; i++)
        {
            scanf("%d",&m);
            while(max[maxp].num<p)
                maxp++;
            while(min[minp].num<p)
                minp++;
            if(m<=max[maxq].value)
            {
                max[++maxq].value=m;
                max[maxq].num=i;
            }
            else
            {
                while(maxq>=maxp&&m>max[maxq].value)
                    maxq--;
                max[++maxq].value=m;
                max[maxq].num=i;
            }
            if(m>=min[minq].value)
            {
                min[++minq].value=m;
                min[minq].num=i;
            }
            else
            {
                while(minq>=minp&&m<min[minq].value)
                    minq--;
                min[++minq].value=m;
                min[minq].num=i;
            }
            s[t]=min[minp].value;
            ss[t]=max[maxp].value;
            t++;
            p++;
        }
    }
    for(i=0; i<t; i++)
        printf("%d ",s[i]);
    printf("\n");
    for(i=0; i<t; i++)
        printf("%d ",ss[i]);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值