题目描述
有一个直方图,用一个整数数组表示,其中每列的宽度为1,求所给直方图包含的最大矩形面积。比如,对于直方图[2,7,9,4],它所包含的最大矩形的面积为14(即[7,9]包涵的7x2的矩形)。
给定一个直方图A及它的总宽度n,请返回最大矩形面积。保证直方图宽度小于等于500。保证结果在int范围内。
测试样例:[2,7,9,4,1],5
返回:14
网上流行的解法是利用一个单调递增栈stack,栈中记录的是列的下标而不是高度,栈始终维护这样一种关系:stack[i]左边第一个高度小于它的列的下标为stack[i-1]。而要保持这种性质就需要在入栈时做些工作:
- 如果栈为空或入栈列的高度不小于栈顶列的高度,则直接入栈。毫无疑问这样肯定满足上述要求;
- 如果入栈列的高度小于栈顶列的高度,这样直接入栈会破坏关系,所以需要将栈顶pop出去,之后要计算一下这个列所能组成的最大矩形面积:假设当前出栈列的下标为i,根据上述性质,这个矩形向左不能超过stack[i-1],向右不能超过当前入栈列的下标k(因为当前入栈列是右边第一次出现高度小于栈顶列)。如此计算stack[i-1]和k之间列的个数再乘上出栈列的高度就是出栈列所能组成的最大矩形面积,然后与当前记录的最大值比较。如果出栈后的栈顶列依然大于入栈列,则循环执行上述操作,直至栈为空或入栈列的高度不小于栈顶列的高度。
代码如下:
import java.util.*;
public class MaxInnerRec {
public int countArea(int[] A, int n) {
LinkedList<Integer> stack = new LinkedList<>();
int result = Integer.MIN_VALUE;
for(int i = 0 ; i <= A.length ; ++i){
int h = i == A.length ? 0 : A[i];
if(stack.isEmpty() || h >= A[stack.peek()]){
stack.push(i);
}
else{
int height = stack.pop();
result = Math.max(result, A[height] * (stack.isEmpty() ? i : i - stack.peek() -1) );
i--;
}
}
return result;
}
}