题目描述:
给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分
思路:
对于第i个矩形,以其高度h[i]能组成的最大矩形是通过如下方式求的:找出i左边第一个高度小于h[i]的,和i右边第一个高度大于h[i]的,用长度乘以h[i]就是了。对于每一个矩形进行这样的操作,找出其中的最大值就行了。
找的过程可以用单调栈来解决,这里以找右边界R[i]为例:从1到n进行遍历,维护一个单调栈(从栈底到栈顶递增),当进入的元素a[i]大于等于栈顶元素时,进栈,否则弹出栈顶元素x,同时说明x的最右边界就是i-1,然后继续判断栈顶元素,直到栈顶元素小于等于a[i],然后把i进栈,继续向后搜索;
所有元素都搜索完毕后,可能有一部分的R[i]==0,说明这些元素的右边界没确定,也就是说,从i到n一直在递增;这些元素一定都还在栈中,处理一下即可。
找出每个i的左右边界之后,取 h[i]*(R[i]-L[i]) 的最大值即可。
代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <stack> 4 #include <cstring> 5 using namespace std; 6 const int MAXN=1e5+5; 7 typedef long long ll; 8 stack<int> S; 9 ll a[MAXN],ans; 10 int R[MAXN],L[MAXN]; //R[i]=k表示a[i]右边的边界是k,其元素是a[k] 11 int main() 12 { 13 int n; 14 while( scanf("%d",&n) && n!=0 ) 15 { 16 memset( a,0,sizeof(a) ); 17 memset( R,0,sizeof(R) ); 18 memset( L,0,sizeof(L) ); 19 ans=0; 20 for(int i=1;i<=n;i++) 21 { 22 scanf("%d",a+i); 23 while( !S.empty() && a[ S.top() ]>a[i] ) 24 { 25 R[ S.top() ] =i-1; //如果遇到连续递增的,则其R[i]=0;否则一定R[i]!=0; 26 S.pop(); 27 } 28 S.push(i); 29 } 30 while( !S.empty() ) //如果栈中还有元素则说明其R[i]=0; 31 { 32 R[ S.top() ]=n; 33 S.pop(); 34 } 35 for(int i=n;i>=1;i--) 36 { 37 while( !S.empty() && a[ S.top() ]>a[i] ) 38 { 39 L[ S.top() ] =i+1; //如果遇到连续递增的,则其L[i]=0;否则一定L[i]!=0; 40 S.pop(); 41 } 42 S.push( i ); 43 } 44 while( !S.empty() ) //如果栈中还有元素则说明其L[i]=0; 45 { 46 L[ S.top() ]=1; 47 S.pop(); 48 } 49 for(int i=1;i<=n;i++) 50 { 51 ll tmp=a[i]*(R[i]-L[i]+1); 52 ans=max( ans,tmp ); 53 } 54 cout<<ans<<endl; 55 } 56 return 0; 57 }