zoukankan      html  css  js  c++  java
  • 单调栈萌新讲解

    单调栈

    哈。。。怎么开始介绍这个单调栈是一个小问题。。。所以就直接讲他的功能了:在入栈时遵循单调原则,可以求出一个元素向左和向右所能扩展的最大长度;

    具体操作:

    例1:求一个元素的右侧的最近比他大的元素位置(BZOJ3401);

    INPUT:

    输入一个n代表元素个数,输入n个元素;

    6

    3 2 6 1 1 2

    OUTPUT:
    输出位置,没有则输出0

    3 3 0 6 6 0

    思路:

    首先能不能随便一点,我就是维护一个栈的单调递增(不管三七二十一),那么我要如何利用呢?

    ①   3进栈;

    ②   2比栈顶元素小,不要;

    ③   6比栈顶元素大,进去;

    ④   。。。。。等等窝们不是要求一个元素比他的最近么?这样子2都不要了。。然后6过来了还进栈。。这不是背道而驰了。

    所以方案错误;

    那么不是维护单调递增,就是维护一下单调递减呗;

    ①   3进栈

    ②    2比3小进栈

    ③   6比2大,咦?一下就是6比2大,而且后面都没有碰到,所以6一定是2的单侧最近,然后2出栈,并且2的答案就是6元素的位置。然后看3,3还是比6小,OK,满足。最后把6进栈。

    ④   1进栈

    ⑤   1进栈

    ⑥   2的时候,栈里面的两个1出栈,然后2进栈

    ⑦    最后注意,栈里面还有6和2这两个元素,可惜没有他们的答案,那就是0;

    int a[100005],ans[100005];
    struct asd{
        int pos;
        int num;	
    };
    stack<asd>q;
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        asd tmp;
        tmp.num=a[1];
        tmp.pos=1;
        q.push(tmp);
        for(int i=2;i<=n;i++)
        {
            while(!q.empty()&&q.top().num<a[i])
            {
                ans[q.top().pos]=i;
                q.pop();
            }
            tmp.num=a[i];
            tmp.pos=i;
            q.push(tmp);
        }
        while(!q.empty())
        {
            ans[q.top().pos]=0;
            q.pop();
        }
        for(int i=1;i<=n;i++)
        {
            if(i>1) printf(" ");
            printf("%d",ans[i]);
        }
        return 0;
    }
    


    引用黄学长的做法:倒序维护单调递减栈,其实也一样,倒序的时候,碰到元素如果比他大就要把栈里元素pop掉,如果比栈顶小的话那就是说栈顶元素位置就是答案;

    所以窝们先可以得出一个小感悟:

    即:单调栈就是通过维护栈内元素单调递增或者单调递减,判断栈顶元素和当前元素的关系处理,然后得到窝们想要的答案(其实就是一个元素向左和向右所能扩展的最大长度);

    这里还有一题(poj2796):实际上就是对于一个元素,求两端的最长延伸;

    题意:给你N个数,求在某段区间的最小值*这段区间所有元素之和,求最大;

    (PS:还是如此窝们只能说我维护一个单调递增看看,行不行?不行递减看看?(或许题目做多了就熟能生巧了吧);我觉得一个栈存一个结点的所需要的所以信息比较好理解,所以上面的代码也是这样。)

    这题的思路:

    首先区间和,利用前缀和,然后减一减就可以搞出来;

    那么就是确定每个元素,当这个元素是最小的时候,我要知道他之前和之和有多少个比他大的,即比他小的最近的两个端点。

    通过上面的写法,可以搞两发单调栈搞出那个区间长度;

    不过还是很欣赏紫忆的这篇(<=可点 >。<);

    维护一个单调递增栈,并且细节上处理一个元素的两个位置,依次从左往右,在当点元素与栈顶元素比较时;

    ①   a[i]>q.top()那么就是入栈;

    ②   a[i]<q.top()时,那么也就是说对于这个元素啊,q.top()的元素的右边最小就是a[i]位置,那么a[i]的前延伸要变成出栈顶元素的前延伸,出栈,那么此时栈不为空的话,栈顶元素的向后延伸位置要变成之前出栈元素的后驱。

    ③   期间判断一个最大值;

    虽然麻烦一点吧,但是还是很妙啊~

    也可以两次,一次操作细节上很多吧;

     嘿嘿嘿~~


  • 相关阅读:
    IT项目管理之系统规划
    项目经理感悟之风险管理
    IT项目管理之系统设计
    IT项目管理之系统验收
    IT项目管理之系统测试
    IT项目管理之系统部署
    大中小型项目管理的区别
    算法评测
    IT项目管理那些事儿
    应用算法的实际情况——简单就是美
  • 原文地址:https://www.cnblogs.com/keyboarder-zsq/p/5934742.html
Copyright © 2011-2022 走看看