题目
给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是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
思路
单调栈为线性复杂度,其中,单调递增栈可以往左/右找到第一个比当前元素大的元素,单调递减栈可以往左/右找到第一个比当前元素小的元素。
遍历每一个小矩形,以当前小矩形的高为高,找到其能组成的最大矩形,即找到其左右第一个比其高小的小矩形。
则两次遍历所有小矩形,第一次从左往右,利用单调递减栈记录小矩形下标,找到每一个小矩形i往右第一个比它矮的小矩形。遍历完成后,若栈中仍有剩余,则意味着剩余的小矩形在后续遍历过程中没有找到比它矮的,即其对应的最大矩形可以一直延伸到最右边,将其r[i]赋为n。第二次同理,得到数组l[i]。
单调递减栈保证了栈中的元素从栈顶到栈底为递减的,即当从左往右遍历到第i个小矩形时,若h[i]<h[s.top()],意味着下标为s.top()的小矩形遇到了第一个比它矮的小矩形i,那么r[s.top()]=i。从右往左同理。
面积S[i]=h[i]*(r[i]-l[I]-1)。
代码
#include <cstdio>
#include <algorithm>
#include <stack>
using namespace std;
int height[100005],r[100005],l[100005];
stack<int> s;
int main() {
int n;
while(scanf("%d",&n)!=EOF&&n!=0){
for(int i=0;i<n;i++)
scanf("%d",&height[i]);
for(int i=0;i<n;i++){
while(s.size()>0&&height[s.top()]>height[i]){
r[s.top()]=i;
s.pop();
}
s.push(i);
}
while(s.size()>0){
r[s.top()]=n;
s.pop();
}
for(int i=n-1;i>=0;i--){
while(s.size()>0&&height[s.top()]>height[i]){
l[s.top()]=i;
s.pop();
}
s.push(i);
}
while(s.size()>0){
l[s.top()]=-1;
s.pop();
}
long long max=0;
for(int i=0;i<n;i++){
long long tmp=(long long)height[i]*(r[i]-l[i]-1);
if(max<tmp)
max=tmp;
}
printf("%lld\n",max);
}
}
总结
本题需要注意数据范围,小矩形的高hi<=109,小矩形的个数<=105,则面积最大可能为1014,远大于int表示范围,故需要采用long long。int型计算的结果为int型,将int型赋给long long型时,需类型转换:long long tmp= (long long) height[i]*(r[i]-l[i]-1)。
题目链接