zoukankan      html  css  js  c++  java
  • 数据结构——单调栈与单调队列

    单调栈

    单调栈是栈内元素具有严格单调性的一种数据结构。

      模板题链接:单调栈

      由于我们要找到每个数左边第一个比它小的数,那么我们便可以发现:

      对于栈中任意一个数,如果在它右边存在一个数比它小(或相等),那么这个数便是不可能被选中的,直接弹出栈即可

      于是我们便可以进行如下操作:

      按序枚举每一个数,准备将当前这个数压栈时,从栈顶开始遍历,如果栈内当前元素比当前预进栈的数要大(或相等),则符合上述所说的性质,可以直接将其出栈,让栈顶位置减一。直到遇到一个数比当前预进栈的数小,则让栈顶位置加一,使其入栈。

      需要注意的是,为了保证栈内必然存在一个数比当前预进栈的数要小,也就是为了防止数组越界,我们可以将栈中下标为0的位置设为-1。

      代码实现:

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    const int N = 1e5+10;
    int n;
    int a[N],top;
    
    int find(int x)
    {
        a[0]=-1;
        while(a[top]>=x)top--;
        if(top==0){a[++top]=x;return -1;}
        int now=a[top];a[++top]=x;
        return now;
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            printf("%d ",find(x));
        }
        return 0;
    }

      单调栈算法,每个元素至多入栈一次、出栈一次,故时间复杂度为O(n)。借助单调栈处理问题的思想在于及时排除不可能的选项,保持策略集合的高度有效性和秩序性,从而为我们作出决策提供更多的条件和可能方法。


      推荐经典习题:Largest Rectangle in a Histogram (POJ2559)

      推荐实战练题:城市游戏


    单调队列

    单调队列与单调栈类似,是一种队列内元素具有严格单调性的数据结构。

      模板题链接:滑动窗口

      下面以求最大值为例:

      对于队列内每一个数,如果在其右边存在一个比它大的数,则该数一定比其更优,故可将其出队

      我们从左到右枚举序列中的每一个数,然后执行以下三步操作:

      1.如果当前队首元素下标已经超出了滑动窗口的范围,则队首元素出队。

      2.若队尾元素小于预入队的数,则不断删除队尾元素,直到队尾元素的值大于该数,则将其插入队尾。

      3.若当前枚举的数的下标已经大于等于滑动窗口的大小,则可以输出,当前队首元素即是最优解。

      为了方便起见,我们在队列中存储数的下标。

      代码实现:

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N = 1e6 + 10;
    
    int n,k;
    int a[N],q[N];
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int front=1,back=1;
        for(int i=1;i<=n;i++)
        {
            if(front<back&&q[front]<=i-k)front++;
            while(front<back&&a[q[back-1]]>=a[i])back--;
            q[back++]=i;
            if(i>=k)printf("%d ",a[q[front]]);
        }
        puts("");
        front=1,back=1;
        for(int i=1;i<=n;i++)
        {
            if(front<back&&q[front]<=i-k)front++;
            while(front<back&&a[q[back-1]]<=a[i])back--;
            q[back++]=i;
            if(i>=k)printf("%d ",a[q[front]]);
        }
        puts("");
        return 0;
    }

      单调队列算法,每个元素至多入队一次、出队一次,故时间复杂度为O(n)。它的思想也是在决策集合(队列)中及时排除一定不是最优解的选择。


      推荐经典习题:最大子序和 (CH1201)


  • 相关阅读:
    无线网破解软件|一键式破解无线网|BT17软件包下载[笔记本+软件就行]
    Boost环境配置及遇到的问题解决方案
    HDU 4255 A Famous Grid
    uva 10306
    系统学习Linux的11点建议
    linux shell except tcl login ssh Automatic interaction
    常用网址记录
    am335x Qt SocketCAN Demo hacking
    a demo for how to use QThread
    OK335xS CAN device register and deiver match hacking
  • 原文地址:https://www.cnblogs.com/ninedream/p/11228646.html
Copyright © 2011-2022 走看看