編程挑戰(8)

在直方圖中,一個長方形由其左邊界和右邊界決定,其最大可能的高度由兩者中的最小者決定。記 R(i,j) 爲由第 i 個直方柱爲左邊界,第 j 個直方柱確定的面積最大的長方形。如果 R(i,j) 的面積最大,那麼,第 i 個直方柱比它的前一個直方柱(如果存在的話),

即第 i-1 個直方柱要高,而 第 j 個直方柱的高度也比第 j+1 個的要高,否則,由 R(i,j+1) 或 R(i-1,j) 的面積比 R(i,j) 還要大,這違背了 R(i,j) 的最優性。


根據這個觀察,我們從第1個直方柱開始,尋找第一個 i, 使得直方柱 i 的高度比 i+1 的大,則 i 是一個可能的右邊界,
而 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;
}


發佈了78 篇原創文章 · 獲贊 8 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章