滑动窗口(双向队列)

问题:

题目来自牛客网~

方法:

设数组元素为ai

解决这个题采用了双向队列,思路的话以求最大值为例,建立一个队列,然后遍历每个a[i],重复执行下面两个步骤

1.如果a[i] > 队尾的元素(说明队尾这个元素已经没有了成为最大值的可能),删除队尾元素,直到队尾元素 > a[i] 或者 队列为空

  如果a[i] < 队尾的元素(则当窗口滑动到这个队尾元素失效的时候,a[i] 有可能成为最大值),将a[i] 放入队列

如果此时 i >= k(窗口满元素) ,输出队头元素

2.从队头位置开始将所有不在窗口范围内的元素删除,因为滑动窗口只是同时判断 k 个元素的最大值

因为队列里直接放置 a[i] 的时候执行操作 2 会不方便,所以我们选择在队列里存放元素的下标 i

最小值同理

代码:

使用STL里 deque 的写法:

#include <iostream>
#include <deque>
#include <cstdio> 
using namespace std;
#define N 1000010

deque <int>q_max;
deque <int>q_min;
int n, k, a[N];

int main(void)
{
    scanf("%d%d", &n,&k);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    //min
    for(int i = 1; i <= n; i++){
    	//去掉不在窗口内的元素
        while(i-q_min.front() >= k) q_min.pop_front();
        //a[i] < 队尾元素,删除队尾开始所有小于a[i]的元素
        while(!q_min.empty() && a[i] < a[q_min.back()]) q_min.pop_back();
        q_min.push_back(i);
        if(i >= k) cout <<a[q_min.front()] <<" ";
    }
    cout <<endl;
	//max
    for(int i = 1; i <= n; i++){
    	//去掉不在窗口内的元素
        while(i-q_max.front() >= k) q_max.pop_front();
        //a[i] > 队尾元素,删除队尾开始所有小于a[i]的元素
        while(!q_max.empty() && a[i] > a[q_max.back()]) q_max.pop_back();
        q_max.push_back(i);
        if(i >= k) cout <<a[q_max.front()] <<" ";
    }
    return 0;
}

使用数组模拟队列写法:

#include <iostream>
#include <cstring>
using namespace std;
#define N 100010

int n, k;
int q[N], a[N];

int main(void)
{
    //输入
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);

    int head = 1, tail = 0;
    for(int i = 1; i <= n; i++){
        //丢掉不在窗口内的元素
        if(tail >= head && i - q[head] + 1 > k) head++;
        //删去不符合条件的尾部元素
        while(tail >= head && a[q[tail]] >= a[i]) tail--;
        //将元素放进队列
        q[++tail] = i;
        //输出
        if(i >= k)
            cout <<a[q[head]] <<" ";
    }

    cout <<endl;

    head = 1, tail = 0;
    for(int i = 1; i <= n; i++){
        //丢掉不在窗口内的元素
        if(tail >= head && i - q[head] + 1 > k) head++;
        while(tail >= head && a[q[tail]] <= a[i]) tail--;
        q[++tail] = i;
        if(i >= k){
            cout <<a[q[head]] <<" ";
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UmVfX1BvaW50

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值