【解析】
使用一个栈来保存输入柱状条,每个柱状条包含两个信息:(1)柱状条的高度(height);(2)柱状条的宽度(width) 。初始宽度均为单位宽度1。
在随后的入栈和出栈中随时更改柱状条的宽度。
(1)当入栈柱状条的高度大于栈顶柱状条的高度或者栈为空时,柱状条入栈;如图1
(2)当入栈柱状条的高度小于栈顶柱状条的高度时,柱状条出栈,同时计算出栈的柱状条的面积,更新最大矩形面积。同时更新当前柱状条的宽度。如图2
(3)当入栈柱状条的高度等于栈顶柱状条的高度时,柱状条出栈,更新当前柱状条宽度。如图3
(4)如果最后栈不空,只剩高度递增的柱状条。一个一个出栈,更新最大矩形面积。每一个柱状条出栈都要更新前一个柱状条的宽度。如图4
写的不好,勿喷。
【代码】
/*********************************
* 日期:2013-11-24
* 作者:SJF0115
* 题号: 寻找直方图中面积最大的矩形
* 来源:http://hero.pongo.cn/Question/Details?ID=58&ExamID=56
* 结果:AC
* 来源:庞果网
* 总结:
**********************************/
#include<iostream>
#include<stack>
#include<vector>
#include<stdio.h>
#include<malloc.h>
using namespace std;
typedef struct Rec{
int height;
int width;
}Rec;
int LargestRectangleArea(vector<int> &height){
int Max = 0,i;
int n = height.size();
//容错处理
if(n <= 0){
return 0;
}
Rec *rec = (Rec*)malloc(sizeof(Rec)*n);
stack<Rec> stack;
//初始化
for(i = 0;i < n;i++){
rec[i].height = height[i];
rec[i].width = 1;
}
for(i = 0;i < n;i++){
int h = rec[i].height;
//如果栈空或者当前高度大于栈顶的矩形高度的时候就压入栈
if(stack.empty() || h > stack.top().height){
stack.push(rec[i]);
}
else{
int preWidth = 0;
//小于栈顶的矩形高度就弹出栈,更新最大的矩形面积
while(!stack.empty() && h < stack.top().height){
rec[i].width += stack.top().width;
//当前面积
int currentMax = stack.top().height * (stack.top().width + preWidth);
//更新最大值
if(Max < currentMax){
Max = currentMax;
}
preWidth += stack.top().width;
//出栈
stack.pop();
}
//等于栈顶的矩形高度
while(!stack.empty() && h == stack.top().height){
rec[i].width += stack.top().width;
stack.pop();
}
//栈空
if(stack.empty() || h > stack.top().height){
stack.push(rec[i]);
}
}
}
//最后栈中只剩递增的序列
int width = 0;
while(!stack.empty()){
int currentMax = stack.top().height * (stack.top().width + width);
if(currentMax > Max){
Max = currentMax;
}
width += stack.top().width;
stack.pop();
}
return Max;
}
int main(){
int i,n,Max,num;
while(scanf("%d",&n) != EOF){
vector<int> height;
for(i = 0;i < n;i++){
scanf("%d",&num);
height.push_back(num);
}
Max = LargestRectangleArea(height);
printf("%d\n",Max);
}
return 0;
}
【方法二】
【解析】
设柱状图为非负整数数组A, 则最大矩形的高度必定是数组的某一项height[i]。
设f(i) 为以数组第i项的高度为矩形高度时矩形的最大宽度,则最大矩形为max{f(i)*height[i]} (0 <= i < n)
f(i)本身无法动态规划,但若将f(i)拆成左右两部分,则很容易动态规划求解
令left(i)为以数组第i项为矩形高度时矩形左侧最大宽度,
right(i)为以数组第i项为矩形高度时矩形右侧最大宽度,
则f(i) = left(i) + right(i) - 1
【代码】
/*********************************
* 日期:2013-11-25
* 作者:SJF0115
* 题号: 寻找直方图中面积最大的矩形
* 来源:http://hero.pongo.cn/Question/Details?ID=58&ExamID=56
* 结果:AC
* 来源:庞果网
* 总结:
**********************************/
#include <stdio.h>
int left[100001],right[100001];
int largestRectangleArea(const int *height,int n) {
int Max = 0,i,j;
//容错处理
if(height == NULL || n <= 0){
return 0;
}
left[0] = 1;
right[n-1] = 1;
//以数组第i项为矩形高度时矩形左侧最大宽度
for(i = 1;i < n;i++){
//初始为单位宽度1
left[i] = 1;
for(j = i-1;j >= 0;){
if(height[i] <= height[j]){
left[i] += left[j];
//跳到下一个比较对象
j -= left[j];
}
else{
break;
}
}
//printf("第%d项左最大宽度:%d\n",i+1,left[i]);
}
//以数组第i项为矩形高度时矩形右侧最大宽度
for(i = n-2;i >= 0;i--){
//初始为单位宽度1
right[i] = 1;
for(j = i+1;j < n;){
if(height[i] <= height[j]){
right[i] += right[j];
//跳到下一个比较对象
j += right[j];
}
else{
break;
}
}
//printf("第%d项右最大宽度:%d\n",i+1,right[i]);
}
for(i = 0;i < n;i++){
int currentMax = (left[i] + right[i] - 1) * height[i];
if(Max < currentMax){
Max = currentMax;
}
}
return Max;
}
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{
int height[] = {1,2,3,4,3,4,3,2,1};
int max = largestRectangleArea(height,9);
printf("%d\n",max);
return 0;
}
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。
【测试数据】
{1,2,3,4,3,4,3,2,1} 结果: 15
{3,4,5,6} 结果:12
{2,1,2,1,2,1} 结果:6
{2,1,5,6,2,3}结果:10
{2, 1, 4, 5, 1, 3, 3, 1, 2} 结果:9