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