Leetcode——84.Largest Rectangle in Histogram && 85.Maximal Rectangle

来源:互联网 发布:上海软件培训班多少钱 编辑:程序博客网 时间:2024/05/23 10:37

直方图中的最大矩形(Largest Rectangle in Histogram)

1.问题描述

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.


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


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.

简单来说,就是给出一个n个非负数,表示直方图每一列的高度,找出直方图中最大矩形的面积。

2.思路

一开始打算使用遍历的方法,比较容易想到也容易理解。方法是使用两层循环,计算从当前位置i开始,到i,i+1,i+2,...到最后一个数的最大矩形面积。算法描述如下:

从i = 0开始到i = heights.size()-1:将当前i的高度记为minh;从j = i开始循环到j = heights.size()-1:minh取当前j列的高度与自身的最小值;Res取minh*(j - i + 1) 和自身的最大值。结束内循环结束外循环

这个算法时间复杂度是O(n2),很容易就超时了。


所以,只能找找其他思路。画图想想。


如上图,从1到3是递增的,然后开始降为2(第二个2),那么3在这里是最高的(比左右高),那它单独一列的面积就可能是最大的(比如说这一列是20),那我们先记下这个面积。


接着对2(第二个2)进行处理,和前面的2(第一个2)是一样高的,通过图可以看到,此时第2,3,4列可以组成一个3x2的矩阵,那我们继续向后遍历,如果下一列是大于等于2的,说明这个矩阵还能更大。所以向后遍历,发现是1,那么只能是先将前面的3x2给计算了,得到6作为最大面积。

接着对1进行处理,1和前面的1一样高,那么继续往后遍历,后面没了,所以计算第一个1到第二个1的面积,是1x5,比6小,所以最大面积是6。

 

根据这个过程,可以采用栈来实现吗?值小的先进,值大的后进但是先出,可以。

 

使用栈来实现,当遍历时,将1,2,3先后入栈,到2时,比3小,所以将栈顶的3弹出,此时栈里面还有数,那么就计算3*(当前位置 - 当前栈顶数所在位置 - 1)= 3,其中当前位置就是遍历到第二个2时的位置,栈顶数也就是第一个2所在的位置,再减去1,取的是这两列中间的部分。得到3。第一次算的最大值maxarea = 3。

 

将第2个2与栈顶比较,与栈顶相等所以入栈,继续往后遍历,遇到最后的1,此时比栈顶小。那么将栈顶的2弹出,此时栈里面还有其他的数,那么计算2*(4 - 1 - 1)= 4,计算得到第2列和第3列的最大矩形面积。结果4比上一个面积3要大,所以maxarea = 4

 

将1与栈顶比较,栈顶是2,所以将栈顶的2弹出,此时栈里还有其他数,那么计算得到的结果是2 * (4 - 0 - 1)= 6,此时maxarea更新为6;


将1与栈顶比较,栈顶是1,所以入栈,继续往后遍历,后面是空。那此时栈顶1弹出,计算1*(5 - 0 - 1) = 4;

将最后一个数弹出,此时栈里没有其他的数了,那么就是说这个数是最小的,此时面积的计算就是1 * 5 = 5。


最后结果maxarea是6。可以发现,计算过程我们需要用到当前位置,以及栈顶数所在位置,所以我们栈里面维护的数值,必需是使用数组下标。通过数组下标也可以得到具体的数值。此外,为了方便计算,在原本heights数组最后push一个-1,算法的描述如下:

从i = 0到i = heights.size()-1:如果栈s为空或者heights[i]的值大于栈顶:那么i入栈,i自增;否则:Top为栈顶的值,并将栈顶出栈;如果此时栈空了:Temp:栈顶的值乘上i;否则Temp:栈顶的值乘上(i - s.top() - 1); 将temp和maxarea作比较,取大的作为maxarea的值;结束循环


这个算法只需要遍历一次heights数组,算法复杂度就只有O(N),比之前那个简陋的思路快了很多,这个思路是参考了其他人的做法,一开始理解起来确实很困难,但是通过画几个图,还是能够理解的。想出这个方法的人也是很厉害呢。


3.代码

int largestRectangleArea_stack(vector<int>& heights) {heights.push_back(-1);int res = 0;stack<int> s;int i = 0;while (i < heights.size()) {if (s.size() == 0 || heights[i] >= heights[s.top()]) {s.push(i);i++;}else {int top = s.top();s.pop();int temp = (s.size() == 0) ? heights[top] * i : heights[top] * (i - s.top() - 1);res = max(res, temp);}}return res;}

最大矩形面积(Maximal Rectangle

1.问题描述

  还有一道与之类似的题目,是Leetcode里面的Maximal Rectangle这道题是求最大矩形面积。给出了一个二维矩阵,矩阵里是10,求1能够成的最大矩阵面积。举个例子,矩阵如下所示:


1  0  1  0  0

1  0  1  1  1

1  1  1  1  1

1  0  0  1  0


2.思路

实际上,这个矩阵可以看成是直方图的形式来处理。自底下上,每一行可以改写成:

4  0  3  0  0

3  0  2  3  2

2  1  1  2  1

1  0  0  1  0


这个矩阵表示的是‘1’的高度,比如说最下面一行,有1的就是1,没1的就是0;往上一行呢,如果有1那就在上一行的基础上加1,这样迭代上去,但是一旦出现0,那就是0;

 

从下往上,对每一行都进行依次直方图求最大矩形面积的计算,每一行的数字正好表示了当前直方图的高度。经过每一行循环计算,可以得到最大的面积值。


3.代码

int maximalRectangle(vector<vector<char> >& matrix) {if (matrix.empty())return 0;int maxarea = 0;vector<int> height(matrix[0].size(), 0);for (int i = matrix.size() - 1; i >= 0; i--){for (int j = 0; j < matrix[i].size(); j++){if (matrix[i][j] == 0)height[j] = 0;elseheight[j] ++;}maxarea = max(maxarea, largestRectangleArea_stack(height));}return maxarea;}


总结

这是一道很经典的题目,在面试中也常常能遇到。这个思路也很难描述清楚,我觉得还是需要自己画图分析之后才能理解。
阅读全文
0 0
原创粉丝点击