题目:输入N个非负整数,分别代表宽度为1,高度为整数值得柱子,从柱状图里找出最大四边形的面积。要求时间复杂度为O(n),空间复杂度为O(n)
举例:输入数组{1,2,3,1,2,3,1,1,1,1},柱状图如图所示,最大四边形的面积为10
对于图中的任意一条柱形,若是求以该柱形的高度为高的最大四边形的面积,需要知道该四边形的边界,该最大四边形的左边界是左方向第一个小于该柱形高度的柱子的右边的柱子,右边界为右方向第一个小于该柱形高度的柱子。
由于要求时间复杂度为O(n),因此数组肯定只能遍历一次。
- 遍历到第一根柱子,高度为1,,左边界是其本身,次时还未确定其右边界,因此,先不计算以该柱子为高的最大四边形的面积。
- 遍历第二根柱子,高度为2,左边界是其本身,次时还未确定其右边界,因此,先不计算以该柱子为高的最大四边形的面积。
- 遍历至第三根柱子,高度为3,左边界是其本身,次时还未确定其右边界,因此,先不计算以该柱子为高的最大四边形的面积。
- 遍历至第四根柱子,高度为1,由于其高度小于前一根柱子,因此,第三根柱子的右边界确定下来,此时开始计算以第三根柱子为高度的最大四边形面积。(规律:我们可以注意到前三根柱子是递增序列,并且前三根柱子的右边界要么是遇到的是第四根柱子(右边遇到的第一根高度下降的柱子),要么是在往后还未遍历到的柱子。只要递增序列后面的第一根高度下降的柱子的高度小于前面的某一根柱子,那么第一根高度下降的柱子即为前面某柱子的右边界。这样依次计算前面以某根柱子的高度为高的最大四边形面积),接下里一次开始计算前面遍历过得柱子分别对应的最大四边形面积,先计算第三根柱子对应的最大四边形面积,然后计算第二根柱子对应的最大四边形面积,第一根。。。。。
- 。。。。。。。同理继续遍历后面的柱子。
以上,在遍历柱子的过程中,可以观察到,具有先进后出 的特性,因此该算法可以利用栈来实现,在栈中存放的是数组元素的下标
以下即为Java 代码实现:
int maxHistogramArea(int[] height){
int n = height.length;
int max = 0;
Stack<Integer> bars = new Stack<Integer>();
bars.add(-1);//为了计算相对距离
for(int i = 0;i < n;i++ ){
int pre = bars.peek();
//符合上升序列,加入栈中
if(pre < 0 || height[i] >= height[pre]){
bars.add(i);
}else{
//一旦下降了,开始依次计算前面遍历过得柱子的面积
pre = bars.pop();
max = Math.max(max,height[pre]*(i-bars.peek()-1));
i--;//还不能确定当前元素是否在上升序列里
}
}
//还未计算的上升序列的面积
while(bars.peek()!=-1){
int pre = bars.pop();
max = Math.max(max,height[pre]*(n-bars.peek()-1));
}
return max;
}