LeetCode OJ 84. Largest Rectangle in Histogram

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

LeetCode OJ 84. Largest Rectangle in Histogram

Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

LeetCode OJ 84. Largest Rectangle in Histogram

The largest rectangle is shown in the shaded area, which has area = 10 unit.

For example,
Given heights = [2,1,5,6,2,3],
return 10.

【题目分析】

题目很容易理解,给定一个非负数组代表的直方图,求出图中包含的最大的矩形的面积。

【思路】

1.这题的一个基本思想是以每一个bar为最低点,向左右遍历直到遇到比他小的bar或边界。这样就能找到一个此bar为最低点的矩形面积。遍历所有的bar之后即可找到最大的矩形面积。但是向左右遍历寻找比他小的bar的时间复杂度是O(n),在加上遍历一遍所有的bar,总的时间复杂度将为O(n*n),是无法通过所有数据的。我们在水平方向任意画一条线,如果有条和这条线相交,我们找出相交的矩阵中最大的那个。示例如下:

当线的高度是2时,相交的矩阵有两个,较大的那个面积是8。

LeetCode OJ 84. Largest Rectangle in Histogram

当线的高度是3时,相交的矩阵有两个,较大的那个面积时6。

LeetCode OJ 84. Largest Rectangle in Histogram

当线的高度是5时,相交的矩阵有一个,面积是10。

LeetCode OJ 84. Largest Rectangle in Histogram

重复上面的步骤,找到的最大值是10.这个过程很简单,只需要遍历所有可能出现的高度,然后找到所有出现的矩阵中面积最大的那一个。但是这个过程的算法复杂度较高,为O(N2).

java代码:

 public class Solution {
public int largestRectangleArea(int[] heights) {
if(heights.length == 0) return 0;
if(heights.length == 1) return heights[0]; int curlen = 0;
int maxS = 0, curS = 0; for(int i = 0; i < heights.length; i++){
curlen = heights[i];
curS = 0;
for(int j = 0; j < heights.length; j++){
if(heights[j] >= preminlen) curS += preminlen;
else{
maxS = Math.max(curS, maxS);
curS = 0;
}
}
maxS = Math.max(curS, maxS);
}
return maxS;
}
}

2. 我们需要寻找一种时间复杂度更低的寻找一个bar左右边界的算法。在网上流传了一个设计极其巧妙的方法,借助一个stack可以将时间复杂度降为O(n)。

这种算法的思想是维护一个递增的栈,这个栈保存了元素在数组中的位置。 这样在栈中每一个左边的bar都比本身小,所以左边就天然有界了,也就是左边界就是左边的一个bar。遍历一遍height数组,在将height数组入栈的时候,如果当前元素height[i]比栈顶元素小,则我们又找到了栈顶元素的右边界。因此我们在此时就可以计算以栈顶元素为最低bar的矩形面积了,因为左右边界我们都已经找到了,而且是在O(1)的时间复杂度内找到的。然后就可以将栈顶元素出栈了。这样每出栈一个元素,即计算以此元素为最低点的矩形面积。当最终栈空的时候我们就计算出了以所有bar为最低点的矩形面积。为保证让所有元素都出栈,我们在height数组最后加一个0,因为一个元素要出栈必须要遇到一个比他小的元素,也就是右边界。

  • 如果已知height数组是升序的,应该怎么做?

比如1,2,5,7,8

那么就是(1*5) vs. (2*4) vs. (5*3) vs. (7*2) vs. (8*1)

也就是max(height[i]*(size-i))

  • 使用栈的目的就是构造这样的升序序列,按照以上方法求解。

但是height本身不一定是升序的,应该怎样构建栈?

比如2,1,5,6,2,3

(1)2进栈。s={2}, result = 0

(2)1比2小,不满足升序条件,因此将2弹出,并记录当前结果为2*1=2。

将2替换为1重新进栈。s={1,1}, result = 2

(3)5比1大,满足升序条件,进栈。s={1,1,5},result = 2

(4)6比5大,满足升序条件,进栈。s={1,1,5,6},result = 2

(5)2比6小,不满足升序条件,因此将6弹出,并记录当前结果为6*1=6。s={1,1,5},result = 6

2比5小,不满足升序条件,因此将5弹出,并记录当前结果为5*2=10(因为已经弹出的5,6是升序的)。s={1,1},result = 10

2比1大,将弹出的5,6替换为2重新进栈。s={1,1,2,2,2},result = 10

(6)3比2大,满足升序条件,进栈。s={1,1,2,2,2,3},result = 10

栈构建完成,满足升序条件,因此按照升序处理办法得到上述的max(height[i]*(size-i))=max{3*1, 2*2, 2*3, 2*4, 1*5, 1*6}=8<10

综上所述,result=10

java代码:

 public class Solution {
public int largestRectangleArea(int[] height) {
int len = height.length;
Stack<Integer> s = new Stack<Integer>();
int maxArea = 0;
for(int i = 0; i <= len; i++){
int h = (i == len ? 0 : height[i]);
if(s.isEmpty() || h >= height[s.peek()]){
s.push(i);
}else{
int tp = s.pop();
maxArea = Math.max(maxArea, height[tp] * (s.isEmpty() ? i : i - 1 - s.peek()));
i--;
}
}
return maxArea;
}
}
上一篇:【推荐】免费,19 款仿 Bootstrap 后台管理主题下载


下一篇:(Problem 33)Digit canceling fractions