滑动最小值(双端队列)

给定一个长度为n的数列a(0),a(1),...,a(n-1)和一个整数k。求数列b(i)=min{a(i),a(i+1),...,a(i+k-1)}(i=0,1,2,3,...,n-k);

限制条件:1<=k<=n<=10^6     0<=ai<=10^9


思路:类似用一个长度为k的窗在整数数列上滑动,求窗里面所包含的数的最小值;
          可以使用RMQ在o(nlogn)复杂度内解决,本次介绍双端队列;
          双端队列(即单调队列),可以在头部和尾部插入和删除元素的数据结构;
          构造单调递增队列,初始双端队列为空,在加入i时,当队列的末尾的值j满足a[j]>=a[i],则不断取出(构造一个递增队列),直到队列为空或者a[j]<a[i]之后再在末尾加入i。则双端队列头部即为最小值。
时间复杂度:由于双端队列的加入和删除都进行了o(n)次,故整个算法的复杂度为o(n);


代码:

//输入
int n,k;
int a[maxn];

int b[maxn];
int deq[maxn];//双端队列

void solve(){
    int s=0,t=0;//双端队列的头部和尾部

    for(int i=0;i<n;i++)//在双端队列的末尾加入i
    { 
         while(s<t&&a[deq[t]]>=a[i])   t--;//加入i时,判断双端队列末尾的值是否满足>=a[i]
         deq[++t]=i;
         if(i-k+1>=0){
             b[i-k+1]=a[deq[s]];//等于双端队列头部
             if(deq[s]==i-k+1)//从双端队列的头部删除元素
                    s++;
          }
      }
      for(int i=0;i<=n-k;i++)
           printf("%d%c",b[i],i==n-k?'\n':' ');
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值