[Leetcode] Largest Rectangle in Histogram
关于问题的描述不再赘述。
算法的主要思路实际上就是要找某一个高度的最右边界和最左边界,所谓最右边界是最后一个比它高或者等于它的索引位置index1,所谓最左边界是第一个比它高或者等于它的索引位置index2。
那么area = height*(index1-index2+1);
这里的核心问题是如何找到他俩。
总结看到的许多博客当中的O(N)的算法,最是感觉写的不是很透彻,在这里我在赘述一遍。
we use a stack to track the increase sequence.
such as 3 6 10, the increase block can be seen as the independent unit to compute
the max area. Because first it has no relation with the former sequence. Such as
4 5 6 7 , 3
before 7 is the increase sequence and the 3 is decrease.
obviously, we can compute the max area from the begin index 4,5,6,7. They have
no relation with 3.
Another case:
4 6 7 8 , 5
we can compute the max area from index 6,7,8. However this does not work on 4, because
4<5. There may be more larger area.
Here the height 8 can be seen as a block, the height after it is not available to
the height before it which is less than it, so we can pop the height 6,7,8 to
compute the height here
独立的递增序列单元是这里的核心思想,这种独立的递增单元具有一定的独立性,其中比当前高度高的高度都应该是和当前高度以及后面的高度都是没有任何关系的。因此我们可以求取以它为高度的长方形的面积。
我们可以使用两个stack来记录这种递增的序列结构:
height记录递增的高度,index记录对应的高度开始的索引位置(当前索引位置不需要记录)
当算法遇到递增结构下降的位置的时候,说明在栈中存放的所以高度比当前高度高的height都可以拿出来进行计算了。所以就从两个栈当中依次取出相应的高度和开始位置,计算长方形的面积,并且对最大的面积进行更新。
算法具体如下:
1 import java.util.*; 2 3 public class Solution { 4 public int largestRectangleArea(int[] h) { 5 Stack<Integer> height = new Stack<Integer>(); 6 Stack<Integer> index = new Stack<Integer>(); 7 int largestArea = 0; 8 for(int i=0;i<h.length;i++){ 9 //每一步loop都会把相应的height放到stack当中,所以每次所进行比较的第一个height就是与其相邻的前一个height 10 if(height.isEmpty()||h[i]>height.peek()){ 11 height.push(h[i]); 12 index.push(i); 13 }else if (h[i] < height.peek()){//如果是相等的时候是没有必要进行计算的 14 int lastindex = 0; 15 while(!height.isEmpty()&&h[i]<height.peek()){ 16 lastindex = index.pop(); 17 int area = height.pop()*(i-lastindex); 18 largestArea = largestArea>area? largestArea:area; 19 } 20 height.push(h[i]); 21 index.push(lastindex); 22 } 23 } 24 while(!height.isEmpty()){ 25 int area = height.pop()*(h.length-index.pop()); 26 largestArea = largestArea>area? largestArea:area; 27 } 28 return largestArea; 29 } 30 }
每一步loop都会把相应的height放到stack当中,所以每次所进行比较的第一个height就是与其相邻的前一个height
这里关键是第17行代码,如何理解?
对于从height栈中弹出的某个height的长方形面积的计算,为什么他的边界是i-lastindex?如果是第一个是很好理解的,根据上面的分析,他们是相邻的。
假设从height栈中不断的弹出的高度和当前高度不是相邻的怎么办?这里还要回到独立递增子结构上来。
假设现在height栈当中保存的是xyz,依次,o是当前的height显然o是别栈顶的height低,所以需要计算高度,实际上计算的第一个面积就是x柱形的面积,我们假设x和y之间不是连续的,那么根据上面的算法,以y为高度的矩形的面积的计算方式是: (index(o)-index(y))*height(y)
为什么呢?实际上上面的图就已经把这个问题说明白了:首先y的开始位置到y之间的部分都是比y高的,x和y虽然不连续,但是他们之间的部分都应该是比他们俩的高度都是高的,所以,可以非常自信的用上面的公式求得一y为高度的矩形的面积。
[1] http://blog.sina.com.cn/s/blog_60a4a1ea0101cwwl.html