1.试题描述
在横轴上放了n个相邻的矩形,每个矩形的宽度为1,而第i(1<<i<<n)个矩形的高度为Hi。这n个矩形构成了一个直方图。例如,下图中六个矩形的高度就分别是3,1,6,5,2,3。
请找出能放在给定直方图里面积最大的矩形,它的边要与坐标轴平行。对于上面给出的例子。最大矩形如下图所示的阴影部分,面积是10.
输入格式:
- 第一行包含一个整数n,即矩形的数量(1<=n<=1000)。
- 第二行包含n个整数h1,h2,…,hn,即相邻的数之间由空格分隔。(1<=hi<=10000)hi为第i个矩形的高度
输出格式:
- 输出一行,包含一个整数,即给定直方图内的最大矩形的面积。
样例输入:
- 6
- 3 1 6 5 2 3
样例输出:
- 10
2.问题分析与实现代码
第一种方法是使用暴力破解,算法复杂度O(n*n) 。先设第一个数为最小值h,然后依次查找矩形比这个数小的,找到最小,计算面积,求出最大值,如此规律计算出所有可能出现的矩形面积结果,最后求出最大值。
#include<iostream>
int main()
{
int n,i,j,h,s,max,a[1001];
cin>>n;
for(i=0;i<n;i++)
cin>>a[i];
max=0;
//从第一个矩形开始,往右扫描,
//若后面的矩形高度比第一个低,
//则h为较低的那个值,不断发生改变
for(i=0;i<n;i++)
{
h=a[i];
for(j=i;j<n;j++)
{
if(a[j]<h)
h=a[j];
s=h*(j-i+1); //矩形面积=长X宽
if(s>max)
max=s;
}
}
第二种方法主要使用栈,时间复杂度O(n)。先找到一个逐步递增的面积,即如果Hi<Hi+1,则最大面积是逐步递增的。这个过程中,将这些Hi放入堆栈中,知道不满足Hi<Hi+1,则最大面积是逐渐递增的。这个过程中,将这些Hi放入堆栈中,知道不满足Hi<Hi+1为止。这个时候,最大的面积可能是最右边Hi,由若干块拼成,从中获得一个最大的面积。出现面积非递增式,则把堆栈中比当前高的直方图弹出,重复上述过程。
#include "iostream"
#include "stack"
#include "vector"
#include "algorithm"
//
using namespace std;
int getMaxArea(vector<int> &hist)
{
stack<int> s;
int i;
int max=0;
int max_area=0;
int tp, area_with_top;
while(i < hist.size())
{
//若栈为空或者栈顶元素小于hist[i],就入栈
if(s.empty() || hist[s.top()] <= hist[i])
s.push(i++);
else
{
//否则,就计算此时的面积,与max_area进行比较
tp = s.top();
s.pop();
area_with_top = hist[tp] * (s.empty() ? i : i-s.top()-1);
if(max_area<area_with_top){
max_area=area_with_top;
}
}
}
while(!s.empty())
{
tp = s.top();
s.pop();
area_with_top = hist[tp] * (s.empty() ? i : i-s.top()-1);
if(max_area<area_with_top){
max_area=area_with_top;
}
}
return max_area;
}
int main()
{
int N;
vector<int> vec;
//输入数据
cin >> N;
for(int i=0;i<N;i++)
{
int val;
cin >> val;
vec.push_back(val);
}
//调用获得最大面积函数
cout << getMaxArea(vec);
}