week5_A最大矩形(单调栈)

题目描述

给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分。
在这里插入图片描述

输入输出

Input

输入包含多组数据。每组数据用一个整数n来表示直方图中小矩形的个数,你可以假定1 <= n <= 100000.
然后接下来n个整数h1, …, hn, 满足 0 <= hi <= 1000000000.
这些数字表示直方图中从左到右每个小矩形的高度,每个小矩形的宽度为1。 测试数据以0结尾。

Output

对于每组测试数据输出一行一个整数表示答案。

Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000

思路分析

该题用到单调栈的数据结构。单调栈既有单调的性质,又满足栈的特点。单调包括单调递增、单调递减、单调非减、单调非增。栈支持push和pop操作,满足先进后出。

对于该题目,我们需要遍历每个矩形,找到以它为高可以向左右扩展的最大长度,求出面积,然后找到最大面积。那么就要考虑能以当前矩形的高为整个矩形的高的条件是什么,也就是向左或向右的矩形的高都大于等于当前这个矩形,即我们向左或向右找到第一个比当前矩形的高矮的矩形就停止寻找

而单调栈正有这样的功能,单调递减栈可以找到向左/向右第一个比当前元素小的元素。因此可以找到以当前元素为最值的最大区间。

注意

1.求面积之后ans会超过int的范围,因此定义时设为long long型。虽然定义的数组a[] R[] L[] st[]均未超int范围,但是求面积时要进行强制类型转换,所以干脆也直接定义成long long型。
2.当前元素与栈顶元素比较时选">“还是”<"依据单调性判断,是否有”=“依据单调递增(减)还是单调非减(增)来判断。

代码

#include<stdio.h>
using namespace std;

const int maxx=1e5+100;
long long a[maxx],R[maxx],L[maxx],st[maxx];
int n;
void findRight()
{//对每个i,向右寻找第一个比它小的位置 
    int top=0;//r是栈顶 
    for(int i=1;i<=n;i++)
    {//注意 a[st[top]]>a[i]有没有等号,依据题目而定 
        while(top>0&&a[st[top]]>a[i]){//top是>0还是>=0要注意 
            R[st[top]]=i-1;
            top--;//因为栈里弹出一个元素,所以栈顶指针减一 
        }
        st[++top]=i; 
    }
    while(top>0){//弹出剩余元素
        R[st[top]]=n;
        top--;
    }
}
void findLeft()
{//对每个i,向右寻找第一个比它小的位置 
    int top=0;
    for(int i=n;i>=1;i--)
    {
        while(top>0&&a[st[top]]>a[i]){
            L[st[top]]=i+1;//注意是i+1,与向右寻找不同 
            top--;
        }
        st[++top]=i;
    }
    while(top>0){
        L[st[top]]=1;
        top--;
    }
} 

int main()
{ 
    while(true){
        scanf("%d",&n);
        if(n==0) break;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        findRight();
        findLeft();
        long long ans=0,tmp=0;
        for(int i=1;i<=n;i++)
        {
        //cout<<R[i]<<" "<<L[i]<<endl;
            tmp=a[i]*(R[i]-L[i]+1);
            if(tmp>ans)
                ans=tmp;
        }
        printf("%lld\n",ans);//printf不取地址,人傻了 
    }
    return 0; 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值