• 单调队列


    单调队列

    算法思想:

    • 先考虑用普通队列来做该如何做,即用一个队列维护窗口,用入队出队模拟窗口移动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;
    }
    
  • 相关阅读:
    SpringMVC将表单对象序列化成Json字符串提交,以List接收
    Spring boot下添加filter
    如何将查出的日期Data类型以Json格式输出到前端
    ajax传递给后台数组参数方式
    Spring boot + Gradle + Eclipse打war包发布总结
    Spring-data-jpa详解
    SpringMVC配置过程中出现的问题!
    spring 集成shiro 之 自定义过滤器
    完全跨域的单点登录
    Java8 Lambda表达式
  • 原文地址:https://www.cnblogs.com/codertea/p/13370950.html
Copyright © 2020-2023  润新知