题意:
给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分。
输入输出格式:
输入包含多组数据。每组数据用一个整数n来表示直方图中小矩形的个数,你可以假定1 <= n <= 100000. 然后接下来n个整数h1, …, hn, 满足 0 <= hi <= 1000000000. 这些数字表示直方图中从左到右每个小矩形的高度,每个小矩形的宽度为1。 测试数据以0结尾。
对于每组测试数据输出一行一个整数表示答案。
样例输入
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
样例输出
8
4000
思路:
确定解题方法:
求最大矩形有两种方法:
1)固定左右端点,找这个区间内矩形高度的最小值
2)固定高度,找可以组成矩形的最左和最右端点(小于固定高度的第一个点)
我采用了类似于第二种方法,采用一次遍历直接的得到矩形宽度
单调栈的应用:
将左边第一个矩形的高度入栈,依次遍历接下来的矩形高度h,若h大于栈顶元素,则说明可以和前面的矩形组成更大的矩形,允许入栈;否则弹栈,直到满足h大于栈顶元素。
矩形宽度确定:
使用wide数组,h每次入栈,将相应的wide置为1,弹栈时,因为单调栈种一定满足靠近栈顶的元素比靠近栈底的元素大,所以弹出的元素一定可以和还未弹出的元素组成更大的矩形,所以后弹出的元素代表的矩形的宽=先弹出的矩形的款+1,即w+=wide[k]
弹栈满足要求后,由于新入栈的元素小于被弹出栈的元素,所以也可以与前面的矩形组成更大的矩形,所以宽度为w+1
注意点:
已知1 <= n <= 100000,0 <= hi <= 1000000000,求面积后可能超过int型表示范围,所以使用long long类型
总结:
1.先明确最大矩形的两种求法
2.合理利用单调栈解决问题
3.注意数据范围,以免出现错误
代码:
#include<cstdio>
using namespace std;
int n;
long long h[100010]; //记录高
long long height[100010],wide[100010]; //记录高度,宽度
int main(){
while(scanf("%d",&n)!=EOF){
if(n==0) return 0;
int k=0;
long long area=0;
for(int i=0;i<n;i++)
scanf("%lld",&h[i]);
h[n]=0; height[0]=0;
for(int i=0;i<n+1;i++){ //固定高,找边界
if(h[i]>=height[k]){
height[++k]=h[i]; wide[k]=1; //入栈
}
else{ //说明到达右边界
int w=0;
while(h[i]<height[k]){
w+=wide[k]; //计算宽度
long long t_area=w*height[k];
if(t_area>area) area=t_area;
k--; //弹栈
}
height[++k]=h[i]; wide[k]=w+1; //入栈
}
}
printf("%lld\n",area);
}
return 0;
}