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);
}