Openjudge 滑动窗口

目录

滑动窗口

要求:

描述:

输入:

输出:

样例输入:

样例输出:

思路分析:

最终代码:


滑动窗口

要求:

总时间限制: 12000ms

内存限制: 65536kB

描述:

 

给定一个长度为n(n<=10^6)的数组。有一个大小为k的滑动窗口从数组的最左端移动到最右端。你可以看到窗口中的k个数字。窗口每次向右滑动一个数字的距离。

下面是一个例子:

数组是 [1 3 -1 -3 5 3 6 7], k = 3。

窗口位置最小值最大值
[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



你的任务是得到滑动窗口在每个位置时的最大值和最小值。

输入:

输入包括两行。
第一行包括n和k,分别表示数组的长度和窗口的大小。
第二行包括n个数字。

输出:

输出包括两行。
第一行包括窗口从左至右移动的每个位置的最小值。
第二行包括窗口从左至右移动的每个位置的最大值。

样例输入:

8 3
1 3 -1 -3 5 3 6 7

样例输出:

-1 -3 -3 -3 3 3
3 3 5 5 6 7

思路分析:

 此题可以说是关于队列的题目中的一个经典难题了. 为了获得最值,一个平凡的想法是利用priority_queue来进行存储,priority_queue存储pair<int,int>,前者是数组中的值,后者是值在数组中的位置,每次push之后的数,再在适当的时候剔除掉前面滑动窗口滑过的数.

***注意:我们不需要存储原有的数组,只需要每次把下一个数scanf就可以了,这样可以省一些空间(此题对空间的要求也是有的)

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
struct Pair{
    int first;
    int second;
    Pair(int a,int b):first(a),second(b){}
    bool operator< (const Pair& y)const{
        if(first == y.first) return second < y.second;
        else return first < y.first;
    }
    bool operator> (const Pair& y)const{
        return y<(*this);
    }
};
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    priority_queue<Pair,vector<Pair>,less<Pair> > q1;
    priority_queue<Pair,vector<Pair>,greater<Pair> > q2;
    int num;
    int Ans[n-k+1];
    for(int i=0;i<k;i++){
        scanf("%d",&num);
        q1.push(Pair(num,i));
        q2.push(Pair(num,i));
    }
    Ans[0]=q1.top().first;
    printf("%d",q2.top().first);
    for(int i=k;i<n;i++){
        scanf("%d",&num);
        q1.push(Pair(num,i));
        q2.push(Pair(num,i));
        while(q1.top().second<=i-k){
            q1.pop();
        }
        while(q2.top().second <=i-k){
            q2.pop();
        }
        Ans[i-k+1]=q1.top().first;
        printf(" %d",q2.top().first);
    }
    printf("\n%d",Ans[0]);
    for(int i=1;i<=n-k;i++){
        printf(" %d",Ans[i]);
    }
    printf("\n");
}

这样的结果可以通过,但是时间接近300ms,我们还可以进一步优化,也就是利用单调队列的思路.

我们利用deque双端队列,手动将它实现成一个单调的队列,其余思路基本相同,这样时间是比优先队列的堆排序会更快的.

以递增队列为例,我们通过递增队列来获得最小值,对于每次新接受的值,我们将其与队列中原有的最后一个值比较,如果最后一个值更大,就把它从队列中剔除,而保留新接受的值.

最终代码:

#include<iostream>
#include<deque>
using namespace std;
typedef pair<int,int> Pair;
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    deque<pair<int,int> > q1,q2;
    const int maxn = 1e6+1;
    int num;
    int Ans1[maxn];
    int Ans2[maxn];
    for(int i=0;i<k;i++){
        scanf("%d",&num);
        /* 保持单调性的操作 */
        while(!q1.empty()&&num<q1.back().first){
            q1.pop_back();
        }
        while(!q2.empty()&&num>q2.back().first){
            q2.pop_back();
        }
        q1.push_back(Pair(num,i));
        q2.push_back(Pair(num,i));    
    }
    Ans1[0]=q1.front().first;
    Ans2[0]=q2.front().first;
    for(int i=k;i<n;i++){
        scanf("%d",&num);
        /* 保持单调性的操作 */
        while(!q1.empty()&&num<q1.back().first){
            q1.pop_back();
        }
        while(!q2.empty()&&num>q2.back().first){
            q2.pop_back();
        }
        q1.push_back(Pair(num,i));
        q2.push_back(Pair(num,i));
        while(q1.front().second<=i-k){
            q1.pop_front();
        }
        while(q2.front().second<=i-k){
            q2.pop_front();
        }
        Ans1[i-k+1]=q1.front().first;
        Ans2[i-k+1]=q2.front().first;
    }
    printf("%d",Ans1[0]);
    for(int i=1;i<=n-k;i++){
        printf(" %d",Ans1[i]);
    }
    printf("\n%d",Ans2[0]);
    for(int i=1;i<=n-k;i++){
        printf(" %d",Ans2[i]);
    }
    printf("\n");
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值