题目
给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是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
解题思路
由于单调栈具有更优的时间复杂度,本题用单调栈解,根据输入数据,分别从左往右、从右往左进行两次单调栈遍历,找出某个点能往左、往右延伸的最大坐标。最后计算面积,取最大值。本题需要注意数据大小,最后计算面积时需要开 long long 。
程序源码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
using namespace std;
int L[100005]{ 0 };
int result[100005]{ 0 };
int resul2[100005]{ 0 };
int stack[100005]{ 0 };
int posi[100005]{ 0 };
int main() {
int n;
while (scanf("%d", &n)) { //读取直方图中小矩形的个数n
if (n == 0) {
break;
}
for (int i = 0; i < n; i++) { //为结束符
scanf("%d", &L[i]);
}
int point = 0, size = 0;
for (int i = 0; i < n; i++) { //从左往右遍历
while (size > 0 && stack[point] > L[i]) { //栈顶元素大于当前元素,出栈
result[posi[point]] = i; //记录出栈位置
point--;
size--;
}
stack[++point] = L[i]; //入栈
posi[point] = i; //记录当前栈对应的元素
size++;
}
while (size > 0) { //取出栈中剩余元素
result[posi[point]] = n; //记录出栈位置
point--;
size--;
}
point = 0, size = 0;
for (int i = n - 1; i >= 0; i--) { //从右往左遍历
while (size > 0 && stack[point] > L[i]) { //栈顶元素大于当前元素,出栈
resul2[posi[point]] = i; //记录出栈位置
point--;
size--;
}
stack[++point] = L[i]; //入栈
posi[point] = i; //记录当前栈对应的元素
size++;
}
while (size > 0) { //取出栈中剩余元素
resul2[posi[point]] = -1; //记录出栈位置
point--;
size--;
}
long long maxs = 0, curs = 0; //计算最大面积
for (int i = 0; i < n; i++) { // 面积 = 高度 * (右端点 - 左端点 - 1)
curs = (long long)L[i] * (long long)(result[i] - resul2[i] - 1);
if (curs > maxs) { //取最大
maxs = curs;
}
}
cout << maxs << endl; //输出
}
return 0;
}