首页 > 其他 > 详细

单调队列

时间:2020-07-24 12:16:57      阅读:62      评论:0      收藏:0      [点我收藏+]

单调队列

算法思想:

  • 先考虑用普通队列来做该如何做,即用一个队列维护窗口,用入队出队模拟窗口移动O(n),线性扫描队列求最值O(k)

  • 当前队列里右面的数比左面的数小(-1,-3),而且左面的数会在右面的数前面出队列,换句话说,只要-1还在,-3一定在,所以最小值一定不会取到-1,所以-1就可以删掉了。即如果后一位的元素比当前的元素小,当前这个元素就没有意义了,删掉。这样把当前队列里面的冗余元素都删掉之后,剩下的元素是递增的。这样求最小值的时候就可以把O(k)优化到O(1),因为只要取队头就好了。求最大值对称地做就可以了。

  • 总结以上步骤和分析过程:1.用普通队列该怎么做

    ? 2.将队列中的没有用的元素删掉----->具有了单调性(当前窗口)

? 3.可以用O(1)时间从队头/队尾取出最值

  • 使用场景:滑动窗口的最值
  • 实现的时候一般手写双端队列(数组模拟)

代码实现:

//例子:滑动窗口
//手写双端队列
//队列里存的是数字在原数组中的下标
int a[N],q[N];
int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    //求最小值
    int hh=0,tt=-1;
    for(int i=0;i<n;i++)
    {
        //判断当前的队头已经不在当前的窗口中
        if(hh<=tt&&q[hh]<i-k+1) hh++;//辐射不到
        while(hh<=tt&&a[q[tt]]>=a[i])   tt--;
        //当前的数加进来
        q[++tt] = i;
        //保证至少有一个窗口
        if(i>=k-1) printf("%d ",a[q[hh]]);
    }
    cout<<endl;
    //求最大值
    hh=0,tt=-1;
    for(int i=0;i<n;i++)
    {
        if(hh<=tt&&q[hh]<i-k+1) hh++;//辐射不到
        while(hh<=tt&&a[q[tt]]<=a[i])   tt--;
        q[++tt] = i;
        if(i>=k-1) printf("%d ",a[q[hh]]);
    }
    cout<<endl;
    return 0;
}

单调队列

原文:https://www.cnblogs.com/codertea/p/13370950.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!