在直方圖中,一個長方形由其左邊界和右邊界決定,其最大可能的高度由兩者中的最小者決定。記 R(i,j) 爲由第 i 個直方柱爲左邊界,第 j 個直方柱確定的面積最大的長方形。如果 R(i,j) 的面積最大,那麼,第 i 個直方柱比它的前一個直方柱(如果存在的話),
而 i 之前的每一根直方柱都是可能是左邊界(因爲 i 是第一個比 i + 1 高的直方柱,所以,在 i 之前的是一個上升的直方柱序列,每一根都比前一根要高)。
這時,我們計算前面所有可能的長方形的面積,並跟當前已知的最大值進行比較,並更新當前已知的最大值(如有必要的話)。然後,我們繼續向前搜索第二個這樣的 i 。
重複這個過程,直到最後一根直方柱。這樣,我們已經遍歷了所有可能是最優解的長方形,並取了其中的最大值,因此,該算法是正確的。
至於時間複雜度,似乎還不太明顯。對每個直方柱,我們通過跟後一個進行比較就知道其是否爲一個可能的右邊界。
如果是,則需要對前面的一個上升序列的每個直方住計算其和 i 確定的最大長方形的面積,
這個上升序列最差情況下似乎有 O(n) 長,時間複雜度最差似乎要 O(n2 )。其實不然,只要注意到,每個可能的左邊界只會被計算一次,
因此,總的時間複雜度爲 O(n)。我們使用一個棧來保存前面的上升直方柱序列,當遇到一個可能的右邊界時,
即第 i-1 個直方柱要高,而 第 j 個直方柱的高度也比第 j+1 個的要高,否則,由 R(i,j+1) 或 R(i-1,j) 的面積比 R(i,j) 還要大,這違背了 R(i,j) 的最優性。
而 i 之前的每一根直方柱都是可能是左邊界(因爲 i 是第一個比 i + 1 高的直方柱,所以,在 i 之前的是一個上升的直方柱序列,每一根都比前一根要高)。
這時,我們計算前面所有可能的長方形的面積,並跟當前已知的最大值進行比較,並更新當前已知的最大值(如有必要的話)。然後,我們繼續向前搜索第二個這樣的 i 。
重複這個過程,直到最後一根直方柱。這樣,我們已經遍歷了所有可能是最優解的長方形,並取了其中的最大值,因此,該算法是正確的。
至於時間複雜度,似乎還不太明顯。對每個直方柱,我們通過跟後一個進行比較就知道其是否爲一個可能的右邊界。
如果是,則需要對前面的一個上升序列的每個直方住計算其和 i 確定的最大長方形的面積,
這個上升序列最差情況下似乎有 O(n) 長,時間複雜度最差似乎要 O(n2 )。其實不然,只要注意到,每個可能的左邊界只會被計算一次,
因此,總的時間複雜度爲 O(n)。我們使用一個棧來保存前面的上升直方柱序列,當遇到一個可能的右邊界時,
把這些可能的左邊界都彈出來,並計算其和右邊界確定的長方形面積。顯然,每個可能的左邊界只會放棧一次。
#include "stdafx.h"
#include <stack>
using namespace std;
typedef stack<int> STACK;
//求出每一個上升長方體的面積最大值
int maxarea(STACK& mystack)
{
int i=0;
int max = 0;
while(!mystack.empty())
{
i++;
int value = mystack.top();
mystack.pop();
int area = value * i;
if (area > max)
{
max = area;
}
printf("value=%d area=%d max=%d\n", value, area, max);
}
printf("----------------------------------------------------\n");
return max;
}
//列出數組中每一個上升的序列
int largestRectangleArea(int arr[], int length)
{
int max= 0;
STACK mystack;
for(int i=0; i<length; i++)
{
mystack.push(arr[i]);
if (arr[i] > arr[i + 1])
{
int area = maxarea(mystack);
if (area > max)
{
max = area;
}
}
}
return max;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[6] = {2, 1, 5, 6, 2, 3};
int length = sizeof(a)/sizeof(int);
int maxarea = largestRectangleArea(a, length);
printf("output the result\n");
printf("maxarea=%d\n", maxarea);
getchar();
return 0;
}