問題描述
在橫軸上放了n個相鄰的矩形,每個矩形的寬度是1,而第i(1 ≤ i ≤ n)個矩形的高度是hi。這n個矩形構成了一個直方圖。例如,下圖中六個矩形的高度就分別是3, 1, 6, 5, 2, 3。

請找出能放在給定直方圖里面積最大的矩形,它的邊要與坐標軸平行。對于上面給出的例子,最大矩形如下圖所示的陰影部分,面積是10。

請找出能放在給定直方圖里面積最大的矩形,它的邊要與坐標軸平行。對于上面給出的例子,最大矩形如下圖所示的陰影部分,面積是10。
輸入格式
第一行包含一個整數n,即矩形的數量(1 ≤ n ≤ 1000)。
第二行包含n 個整數h1, h2, … , hn,相鄰的數之間由空格分隔。(1 ≤ hi ≤ 10000)。hi是第i個矩形的高度。
第二行包含n 個整數h1, h2, … , hn,相鄰的數之間由空格分隔。(1 ≤ hi ≤ 10000)。hi是第i個矩形的高度。
輸出格式
輸出一行,包含一個整數,即給定直方圖內的最大矩形的面積。
樣例輸入
6
3 1 6 5 2 3
3 1 6 5 2 3
樣例輸出
10
思路:第一次看見這題的想法就是:
1、先輸入數據,存入一個數組里
2、遍歷數組中的每個元素,并找出當前數組元素左邊和右邊第一個小于當前數組元素的數
3、由剛才得到的數組元素的下標,計算這段距離中有多少個矩形,
4、當前元素 * 距離 = temp
5、比較最終答案和temp,如果temp大于最終答案ans,那么ans = temp,否則繼續
但是提交之后發現會超時,每次反復的運算大大增加了時間復雜度,所以筆者從別人那里借鑒到一種方法:
這種方法的大體思路是這樣的,輸入數據之后,遍歷每個數據,對于其中的每一個數據a[i], 從下表i到n-1之間,找到最小的數a[j],用它乘以i到j之間矩形的個數,如果得到的答案大于最終要輸出的答案,那么就把這個答案賦值給最終答案。
說的比較籠統,一會再深入講解,先看看代碼:
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #include<string> 5 #include<cstring> 6 using namespace std; 7 const int N = 1003; 8 int a[N]; 9 10 int main(){ 11 int n; 12 while(cin>>n){ 13 for(int i =0 ;i < n;++i){ //輸入數據 14 cin>>a[i]; 15 } 16 int ans = -1; //先設置最終答案ans為-1 17 for(int i = 0 ; i< n;++i){ //對于每個元素a[i] 18 int low = a[i]; //當前最小值low設置為a[i] 19 for(int j = i ; j < n;++j){ //對于i后面的每個元素 20 if(low > a[j]) //如果a[j] 比 當前設置的最小值還要小,那么最小值設置為a[j] 21 low = a[j]; 22 int temp = (j - i + 1) * low; //設置標記變量temp 為這段區間中的總和 23 if(temp > ans) 24 ans = temp; 25 } 26 } 27 cout<<ans<<endl; 28 } 29 return 0; 30 }
我想還有許多人對二層循環那里不明白,其實筆者剛開始也不太明白,下面就來講解一下這里吧、、、
有一個問題,就是總是向右邊遍歷,那么左邊的數據怎么算?
其實,在不斷向右邊遍歷的過程中,我們如果把下標 i? 看成后面每個數的左邊界就好了、、、
假如 i 現在為0,那么右邊的每個數的左邊界都是 0,并且按照代碼中寫的,不斷找到i 到j之間的最小值,那么 0 到 i 之間的最小值的最終結果是不是就是n * 最小值呢
如果還不明白,還可以這么想,假如就三個數據,a1,a2,a3, 假如a1 比a2 小的前提下,
(1)a3 大于 a2 并且大于 a1 那么對于a3來說,最大值就是a3
(2)a3小于a2 并且大于a1 ,那么對于a3來說,最大值就是a3 * 2
、、、、、
所以從前向后遍歷的過程,其實就是不斷對于下標為i后面的某個元素j的左方向遍歷過程、、、
大家懂了嗎,如果還有問題,希望大家能提出來,筆者深知能力有限,但是能幫助大家的還是會盡力的、、