HDU1506 / POJ2339 Largest Rectangle in a Histogram 单调递减栈

1.什么是单调栈

  • 具有单调性和栈的性质
  • 单调递减栈就是从栈底到栈顶是单调递减的
  • 单调递增栈就是从栈底到栈顶是单调递增的

2.单调栈解决的问题

  • 以自己为最小值,找到最长的区间;单调递增栈
  • 以自己为最大值,找到最长的区间;单调递减栈
  • 给定一个区间找到这个区间的最大值或最小值

3.单调递减栈的性质

  • 对于第一个出栈的元素,它的右宽一定为0
  • 对于第二个出栈的元素,它的右宽为第一个出栈元素的总宽
  • 对于第三个出栈的元素,它的右宽为第二个出栈元素的总宽
  • 。。。。。。。。
  • 直到栈顶元素小于自己,才可以入栈;
  • 入栈元素的左宽为上次出栈元素的总宽+1(自身);若无出栈元素,则左宽为1(自身)
  • 最后将栈中所有元素出栈,考虑所有情况

(左宽就是左边比自己小的元素个数,右宽就是右边比自己小的元素的个数)

4.以下面数据模拟一下单调递减栈的操作

  1. 1入栈,无出栈元素,左宽为1;
  2. 5入栈,无出栈元素,左宽为1;
  3. 5出栈,第一个出栈右宽为0;
  4. 4入栈,左宽为上个出栈元素的总宽+1=2;
  5. 8入栈,无出栈元素,左宽为1;
  6. 8出栈,第一个出栈,右宽为0;
  7. 6入栈,左宽为上个出栈的总宽+1;
  8. 7入栈,无出栈元素,左宽为1;
  9. 7出栈,第一个出栈,右宽为0;
  10. 6出栈,第二个出栈,右宽为上个元素的总宽:1;
  11. 4出栈,第三个出栈,右宽为上个元素的总宽:3;
  12. 3入栈,左宽为上个出栈的总宽+1:6;
  13. 3出栈,第一个出栈右宽为0;
  14. 2入栈,左宽为上一个出栈的总宽+1:7;
  15. //全部出栈:
  16. 2出栈,第一个出栈,右宽为0;
  17. 1出栈,第二个出栈的,右宽为上个出栈的总宽:7;

5. 单调栈的实现

hdu1506(单调递减栈)poj2339,hrbustoj 2326(需long long)

单调递减栈:如果是以各个元素为最大值找到最大区间的话  q[0]=inf, h=inf-1;

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
//int a[maxn];
int q[maxn]={-1};
int w[maxn];//记录左宽,从这个点之前有多少个点的高度大于等于当前点的高度
int main()
{
    int n,h;
    while(scanf("%d",&n)&&n)
    {
        int top=0;
        ll ans=0;
        for(int i=1;i<=n+1;i++)
        {
            if(i!=n+1)
                scanf("%d",&h);
            else
                h=0;//为了让所有元素出栈
            if(h>q[top])
                q[++top]=h,w[top]=1;
            else
            {
                ll cnt=0;  //第一个出栈的右宽为0;
                while(h<=q[top])
                {
                    ans=max(ans,(w[top]+cnt)*q[top]);  //(左宽+右宽)*高度;
                    cnt=cnt+w[top--];  //第(i>1)出栈的右宽为上一个的总宽;
                }
        //终于找到比自己小的数字了,可以入栈了,入栈会得到左宽,左宽为上一个出栈元素的总宽+1;
                q[++top]=h;
                w[top]=cnt+1;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
//单调栈:从栈顶到栈底单调递减

猜你喜欢

转载自blog.csdn.net/qq_40507857/article/details/83959946