单调栈

单调栈

单调栈就是字面意思,具有单调性的栈。而这次我要用到的是单调递增的单调栈。单调栈的操作很简单,我们可以先让栈底的值为0或者负数,只要判断那个数是否大于栈顶的数,大于就入栈,否则就把栈顶出栈直到栈空或者这个数大于栈顶。
一个单调递增栈的例子:
进栈元素分别为3,4,2,7,4,5,1,3
3进栈:(3)
4进栈:(3,4)
3,4出栈,2进栈:(2)
7进栈:(2,7)
7出栈,4进栈:(2,4)
5进栈:(2,4,5)
2,4,5出栈,1进栈:(1)
3进栈:(1,3)

下面是一个适合用单调栈解决的题目,可以省很多时间。
题目——直方图中的最大矩形
通常,直方图用于表示离散分布,例如,文本中字符的频率。
现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。
图例右图显示了所描绘直方图的最大对齐矩形。
输入格式
输入包含几个测试用例。
每个测试用例占据一行,用以描述一个直方图,并以整数n开始,表示组成直方图的矩形数目。
然后跟随n个整数h1,…,hn。
这些数字以从左到右的顺序表示直方图的各个矩形的高度。
每个矩形的宽度为1。
同行数字用空格隔开。
当输入用例为n=0时,结束输入,且该用例不用考虑。
输出格式
对于每一个测试用例,输出一个整数,代表指定直方图中最大矩形的区域面积。
每个数据占一行。
请注意,此矩形必须在公共基线处对齐。
数据范围
1≤n≤100000,
0≤hi≤1000000000
输入样例:
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
输出样例:
8
4000
直方图是由在公共基线处对齐的一系列矩形组成的多边形。
矩形具有相等的宽度,但可以具有不同的高度。
例如,图例左侧显示了由高度为2,1,4,5,1,3,3的矩形组成的直方图,矩形的宽度都为1:
在这里插入图片描述

在这里插入图片描述
该题可以暴力枚举,把每种情况的矩形面积都计算出来并且存起来,最终求出最大值即可,但是估计会时间超限。而利用单调栈就可略过很多不必要算的矩形,可以省下很多时间。
核心代码如下

 for(i=1;i<=n+1;i++)
        {
            if(a[i]>s[j])//单调栈入栈操作
            {
                s[++j]=a[i];
                w[j]=1;//利用w数组记录宽度,到后面出栈时便于统计
            }
            else
            {
                int wide=0;//wide用于统计宽度用来计算面积
                while(s[j]>a[i])//出栈并且计算面积
                {
                    wide+=w[j];//这里是关键点,统计出栈的宽度,因为出去的都是比现在栈顶要大的元素,所以用栈顶元素算面积时,出栈的元素一定会满足该高度,所以把它们都要算进去,而且出去的一定是满足条件并且与其相邻的
                    m=(long long int)s[j]*wide;//m为面积,因为s和wide数据类型都为int所以要强制转换
                    if(ans<m)//求最大面积
                        ans=m;
                        j--;//出栈
                }
                s[++j]=a[i];//把算完面积的这个元素入栈,更新栈顶
                w[j]=wide+1;//其宽度就包括了那些与它相邻又大于它的出栈元素,接下来计算这一块直方图最大矩形面积的最大高度也只能用现在这个栈顶的高度,否则现在栈顶的高度不满足矩形高度,这里就用一个含带了之前能利用的方块,所以省掉了很多步骤
            }
        }

简述单调栈做这个题的巧妙之处,就是每次栈顶的宽度包含了之前出栈元素的宽度(而之前出栈的元素又一定大于现在栈顶的元素,所以一定会满足以现在栈顶形成的矩形),能巧妙的计算最大矩形面积。每次出栈一个元素才会计算一次面积,所以节省很多时间。比如说这个数组完全是单调递增的,那就直接入栈,最后一次次出栈计算面积,就相当于从最右边(高度最大)的矩形向左边延伸,一次次降低高度并且增大宽度,得出最大的面积。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值