题目
题意
给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是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
题目大意
本题依次给出数轴上若干个宽为1的矩形的高,如图所示。要求得到图中覆盖最大矩形的面积。例如本题图片中阴影部分为最大矩形面积。
解题思路
本题需要用单调栈的思路来完成,首先录入每个矩形的高和对应下标,保存在结构体 node 中。随后维护两个单调不减栈,同时对于每一个矩形,维护以它的高度为最小高度的大矩形的左右边界 x[i] 与 y[i] ,即维护两个数组。随后开始先自左往右向一个单调栈中压元素,每压入一个新的元素时,要从栈顶开始弹出所有高度大于等于新元素的数据,当找到小于新元素的数据,那么该元素的下标就是对应大矩形左边界,此时注意如果弹出到最后栈空了,则左边界为第一个矩阵。之后开始从右向左进行和上述相似的操作,此处注意当栈空时右边界为最后一个矩阵下标。
单调栈的维护是找到每个小矩形对应左右边界 x[i] 和 y[i] 的关键所在。本题归根结底就是求左右两边第一个比 height[i] 小的位置,这是单调栈的典型运用。同时单调栈复杂度不高,只需要O(n)的时间复杂度即可完成。
每个小矩形对应左右边界找到之后,遍历所有高度,得到最大的 height[i] * ( y[i] - x[i] + 1 ) 就是最终结果。
具体代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#define ll long long
#define ld long double
using namespace std;
struct node{
ll num; //注意数据范围
int index;
node(int a, int b)
{
num = a;
index = b;
}
node()
{
num = 0;
index = 0;
}
}l[100005];
int x[100005],y[100005];
int main()
{
int n;
while(true)
{
cin >> n;
if(n == 0)
{
break;
}
for(int i = 1; i <= n; i++)
{
cin >> l[i].num;
l[i].index = i;
}
stack<node> fr;
fr.push(node(-1,0));
for(int i = 1; i <= n; i++)
{
while(fr.top().num >= l[i].num)
{
fr.pop();
}
x[i] = fr.top().index + 1;
fr.push(l[i]);
}
stack<node> ba;
ba.push(node(-1,n+1));
for(int i = n; i >= 1; i--)
{
while(ba.top().num >= l[i].num)
{
ba.pop();
}
y[i] = ba.top().index - 1;
ba.push(l[i]);
}
ll ans = 0;
for(int i = 1; i <= n; i++)
{
ans = max(ans,(y[i]-x[i]+1)*l[i].num);
}
cout << ans << endl;
}
return 0;
}