单调递减队列

题意:

给定一个长度为n的序列,有一个长度为k的滑动窗口,窗口从左向右依次移动,求每次移动时窗口中的最大值。


算法实现:
1.有一种很常见的算法,时间复杂度为O(n*k)的算法,线性遍历每个数再求每个滑动窗口中的最大值,、但当k很大的时候非常耗时。

2.还有一中就是单调递减队列,可以把时间复杂度优化到接近O(n),既然是单调队列,那我们就要定义一个队列,而且还要是双端的。下面我们模拟一下。



假定这个序列的k为3,那我们从第一个元素开始访问,这个时候我们有一个空的双端队列que。我们先把第一个元素及下标入队,队列为{(1,1)},然后开始访问第二个元素,把第二个元素的值与第一个元素的值比较,如果小于则往队列后面加,否则将他前面的一个元素删除,直至遇到比它大的为止,然后将它加入队列。这个队列中就变成了{(3,2)}。继续操作,队列变成{(3,2),(-1,3)}、{(3,2),(-1,3),(-3,4)}、{(3,2),(-1,3),(-3,4),(-4,5)},而这时,我们可以看到队列中的元素个数大于了k,而这时我们应该判断队首元素下标是否小于i-k+1,如果小于则删除队首元素。依照此操作重复进行,直到整个序列遍历完成。在我们入队的时候其实可以只入队下标,用下标来查找元素。


代码如下:

#include<iostream>
#include<cstdio>
#include<deque>
using namespace std;

int n,k;
int cnt = 0;
int a[100002];
int id[100002];
int ans[100002];

deque<int>que;

void getmax(){
    for(int i = 1;i <= n; i++){
        while(!que.empty() && a[que.back()] <= a[i])que.pop_back();//比较并删除元素
        que.push_back(i);//添加元素
        while(!que.empty() && que.front() < i-k+1)que.pop_front();//检查是否超出k
        ans[cnt++] = que.front();//记录答案
    }
}

int main(){
    scanf("%d%d",&n,&k);
    for(int i = 1;i <= n; i++)scanf("%d",&a[i]);
    getmax();
    for(int i = k-1;i < cnt; i++)printf("%d ",a[ans[i]]);//输出要从k-1开始输出。
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值