现在的位置: 首页 > 综合 > 正文

编程挑战(8)

2019年01月11日 ⁄ 综合 ⁄ 共 1495字 ⁄ 字号 评论关闭

在直方图中,一个长方形由其左边界和右边界决定,其最大可能的高度由两者中的最小者决定。记 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;
}

抱歉!评论已关闭.