• 单调栈


    转载自:https://blog.csdn.net/zuzhiang/article/details/78134247

    定义:

    单调栈,顾名思义,是栈内元素保持一定单调性(单调递增或单调递减)的栈。既然是栈,就满足后进先出的特点。与之相对应的是单调队列。

    单调栈有以下两个性质:
    1、若是单调递增栈,则从栈顶到栈底的元素是严格递增的。若是单调递减栈,则从栈顶到栈底的元素是严格递减的。
    2、越靠近栈顶的元素越后进栈。

    3、利用单调栈,可以找到从左/右遍历第一个比它小/大的元素的位置

    从当前元素a[i]开始向左边找第一个比a[i]小的值/

     for (int i = 0; i < n; i++)
            {
                while (!p.empty() && a[p.top()] >= a[i])//按照大于等于a[i]的规则,从a[i]开始,向左边可以延伸最远的数的下标
                    p.pop();
                if (p.empty())//说明a[i]左边的所有数都大于等于a[i]
                    l[i] = 0;
                else//找到就记录从a[i]开始向左边寻找大于等于a[i]的最大边界下标
                    l[i] = p.top() + 1;
                p.push(i);
            }

     从当前元素a[i]开始向右边找第一个比a[i]小的值

    while (!p.empty())//记得清空栈
                p.pop();
            for (int i = n - 1; i >= 0; i--)//往右边找第一个比a[i]小的数
            {
                while (!p.empty() && a[p.top()] >= a[i])
                    p.pop();
                if (p.empty())
                    r[i] = n - 1;
                else
                    r[i] = p.top() - 1;
                p.push(i);
            }

    实现:

    例如实现一个单调递增的栈,比如现在有一组数10,3,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。


    10入栈时,栈为空,直接入栈,栈内元素为10。

    3入栈时,栈顶元素10比3大,则入栈,栈内元素为10,3。

    7入栈时,栈顶元素3比7小,则栈顶元素出栈,此时栈顶元素为10,比7大,则7入栈,栈内元素为10,7。

    4入栈时,栈顶元素7比4大,则入栈,栈内元素为10,7,4。

    12入栈时,栈顶元素4比12小,4出栈,此时栈顶元素为7,仍比12小,栈顶元素7继续出栈,此时栈顶元素为10,仍比12小,10出栈,此时栈为空,12入栈,栈内元素为12。

    伪代码

    /*
    * 本伪代码对应的是单调递减栈 
    *共n个元素,编号为0~n-1
    */
    while(栈为空) 栈顶元素出栈; //先清空栈
    a[n]=-1;
    for(i=0;i<=n;i++)
    {
        if(栈为空或入栈元素大于等于栈顶元素) 入栈;
        else 
        {
            while(栈非空并且栈顶元素大于等于入栈元素)
            {
                栈顶元素出栈;
                更新结果; 
            } 
            将最后一次出栈的栈顶元素(即当前元素可以拓展到的位置)入栈; 
            更新最后一次出栈的栈顶元素其对应的值; 
        }      
    }
    输出结果; 

    应用:

    以上就是一个单调栈的定义及其实现,下面就来说一下它可以解决哪些问题。其实我也不能给出证明,以证明它为什么能完成这些功能,只是简单的把它的用途说一下,碰到问题时就需要大家灵活运用了。


    1.最基础的应用就是给定一组数,针对每个数,寻找它和它右边第一个比它大的数之间有多少个数。

    2.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大。

    3.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大。

    实战练习:

    一、应用一:poj3250 单调递减栈

    https://www.cnblogs.com/-citywall123/p/10769634.html

    二、应用二:poj 2559 单调递增栈

    https://www.cnblogs.com/-citywall123/p/10770468.html

    三、应用三:poj 2796

    https://www.cnblogs.com/-citywall123/p/10770825.html

  • 相关阅读:
    ueditor单独调用图片上传
    百度Ueditor多图片上传控件
    linux基础之vim编辑器
    linux基础之进阶命令二
    linux基础之基础命令一
    Python基础之PyCharm快捷键大全
    IT菜鸟之VTP应用项目
    IT菜鸟之总结(Du teacher)
    IT菜鸟之DHCP
    IT菜鸟之路由器基础配置(静态、动态、默认路由)
  • 原文地址:https://www.cnblogs.com/-citywall123/p/10759351.html
Copyright © 2020-2023  润新知