一个直方图是由许多矩形组成,在给定的直方图中找出最大的矩形面积。同时,为了简化问题,假定所有矩形宽度都为1个单位。例如,下面的直方图中有6个矩形,高度分别是(6,7,8,4,5,3)。最大的矩形面积是18(如下图所示,最大矩形面积用红色方框标出)
下面给出的解决方法时间复杂度为O(n)。矩形面积的计算公式为底*高。对于求直方图中的最大矩形面积。就是以某个矩形的高度为高,确定其左右边界。确定两个边界后就可以得到宽度,从而最终计算出面积。这里最难理解的就是左右边界。如何取得它的左右边界。我们从左向右遍历每个矩形,并通过一个栈来存储这些矩形高度在输入数组中的索引(如定义一个整型数组height[n]={6,7,8,4,5,3}表示直方图中各矩形的高,栈里面保存该数组的下标,即这些矩形高度在数组中的索引)。每个矩形(索引)仅压入栈中一次。当输入的矩形高度大于栈顶矩形的高度,或者当栈为空时,将当前矩形高度的数组索引入栈,当输入的矩形高度小于栈顶矩形的高度,那么栈顶矩形将会被弹出,然后计算矩形面积,其中矩形面积的高为弹出单个矩形条的高。现在得到了高,接下来得到左右边界后便可计算出宽度。由于当前输入的矩形i的高度小于栈顶矩形,那么以栈顶为高的矩形右边界为i。当前栈若非空,那么栈中矩形条的高度一定是小于等于弹出的矩形的高度,因此左边界就确定了。如果栈不为空,则弹出矩形的宽度则为(i-peek()-1).否则,矩形宽度为i.
最终算法步骤归纳为:
- 创建一个空栈
- 从第一个矩形条开始,对每个矩形条的高度height[i] (i的取值范围是[0,n-1])执行下面两步
a) 如果栈为空,或height[i]大于等于栈顶元素,那么将矩形条i压入栈中。
b)如果输入的矩形条高度小于栈顶元素高度,那么将栈顶元素在输入数组中的索引top出栈,然后计算矩形面积。矩形的高为height[top],而右边界为i,左边界为当前栈顶元素对应的索引,若栈为空,则宽度就是i。 - 经过计算后,栈过非空,然后将栈中元素逐个弹出,并按照步骤2计算矩形面积,并且更新最大值。下面的代码是纯C语言实现。先定义了栈,栈的大小指定为10.实际应用中,可灵活使用,改变其大小。
/*求直方图的最大矩形面积*/ #include <stdlib.h> #include <stdio.h> typedef int ElemType; struct StackSq{ ElemType *stack; int top; int MaxSize; }; void InitStack(struct StackSq *s) { s->MaxSize=10;/*置栈空间初始最大长度为10*/ s->stack=(int *)malloc(10*sizeof(ElemType));/*动态存储空间分配*/ s->top=-1;/*置栈为空*/ } //1 void Push(struct StackSq* S,ElemType x) { // if(S->top==S->MaxSize-1)againMalloc(S);/*若栈空间用完则重新分配更大的存储空间*/ S->top++;/*栈顶指针后移一个位置*/ S->stack[S->top]=x;/*将新元素插入到栈顶*/ } //2 ElemType Pop(struct StackSq* S) { if(S->top==-1){ printf("栈空,无元素出栈!\n"); exit(1); } S->top--; return S->stack[S->top+1]; } //3 ElemType Peek(struct StackSq* s) { if(s->top==-1){ printf("栈空,无元素出栈!\n"); exit(1); } return s->stack[s->top]; } int EmptyStack(struct StackSq* S) { if(S->top==-1) return 1; else return 0; } int largestRectangleArea(int height[],int n) { struct StackSq s; InitStack(&s); int max_area = 0; // 最大矩形面积 int top; // 栈顶 int area_with_top; int i = 0; while (i < n) { if (EmptyStack(&s) || height[Peek(&s)] <= height[i]) { Push(&s,i++); } else { top=Pop(&s); area_with_top = height[top] * ((EmptyStack(&s) ? i : i -Peek(&s)- 1));//这个非常重要,求宽度。 max_area = max_area>area_with_top?max_area:area_with_top; } } while (!EmptyStack(&s)) { top=Pop(&s); area_with_top = height[top] *((EmptyStack(&s) ? i : i -Peek(&s)- 1)); max_area = max_area>area_with_top?max_area:area_with_top; } return max_area; } /*测试*/ int main(int argc, char *argv[]) { int height[]={6,7,8,4,5,3}; printf("the area of the Largest Rectangle in Histogram is %d",largestRectangleArea(height,6)); }