题目链接:https://leetcode.com/problems/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.
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 height = [2,1,5,6,2,3]
,
return 10
.
思路:我记得很清楚昨天晚上睡觉之前写了一篇这题的解题报告,怎么今天一看没了呢?好吧,重写写一篇吧!
这题的一个基本思想是以每一个bar为最低点,向左右遍历直到遇到比他小的bar或边界。这样就能找到一个此bar为最低点的矩形面积。遍历所有的bar之后即可找到最大的矩形面积。但是向左右遍历寻找比他小的bar的时间复杂度是O(n),在加上遍历一遍所有的bar,总的时间复杂度将为O(n*n),是无法通过所有数据的。因此我们需要寻找一种时间复杂度更低的寻找一个bar左右边界的算法。在网上流传了一个设计极其巧妙的方法,借助一个stack可以将时间复杂度降为O(n),真是让人叹为观止,原作者好像是个老外。
这种算法的思想是维护一个递增的栈,这个栈保存了元素在数组中的位置。 这样在栈中每一个左边的bar都比本身小,所以左边就天然有界了,也就是左边界就是左边的一个bar。遍历一遍height数组,在将height数组入栈的时候,如果当前元素height[i]比栈顶元素小,则我们又找到了栈顶元素的右边界。因此我们在此时就可以计算以栈顶元素为最低bar的矩形面积了,因为左右边界我们都已经找到了,而且是在O(1)的时间复杂度内找到的。然后就可以将栈顶元素出栈了。这样每出栈一个元素,即计算以此元素为最低点的矩形面积。当最终栈空的时候我们就计算出了以所有bar为最低点的矩形面积。为保证让所有元素都出栈,我们在height数组最后加一个0,因为一个元素要出栈必须要遇到一个比他小的元素,也就是右边界。
现在我们以height[2, 1, 5, 6, 2, 3]为例来分析其入栈出栈操作是如何完成的:
1. 首先栈为空,则2在数组中的位置0入栈,现在栈顶为元素2在数组中的位置0
2. 遍历到1的时候,发现1比栈顶元素height[0]小,因此栈顶元素height[0]的左右边界都找到了,将0出栈,并计算以栈顶元素height[0]为最低bar的矩形面积为2。0出栈之后栈为空
3. 此时将元素1的位置1入栈,此时栈顶为元素1在数组中的位置1
4. 再将元素5的位置2入栈,此时栈顶为元素5在数组中的位置2
5. 再将元素6的位置3入栈,此时栈顶为元素6在数组中的位置3
6. 遍历到2的时候发现2比栈顶元素height[3]即6小,因此6的左右边界都已找到,此时即可将3出栈,并计算以栈顶元素height[3]为最低点的矩形面积为6。此时栈顶为元素5在数组中的位置2。
7. 然后遍历到元素2再和栈顶元素比较,发现卧槽还是不能入栈,因此只能再把栈顶元素赶出来了。然后2出栈,并计算以5为最低点的矩形面积,此时矩形的宽度为2,因为元素5在数组中的位置为2,元素2在数组中的位置为4。因此以5为最低点的面积为5*2 = 10。此时栈顶为元素1在数组中的位置1。
8. 然后2再和栈顶1元素相比较发现,啊!终于碰到一个比我小的了,然后2的位置4就入栈做了栈顶
9. 再将3的位置5入栈,此时栈顶为3的位置5
10. 此时遍历到了我们自己加进去的0,比较发现0比栈顶元素小,然后栈顶5出栈,并计算以3为最低点的矩形面积为3。此时栈顶元素为4。
11. 将0和栈顶的值2比较,发现0比栈顶值小,因此4出栈,并计算以2为最低点的矩形的面积。2的右边界是0, 0元素在数组中的位置为6, 2的左边界是元素1,元素1在左边的1,因此以元素2为最低点的矩形面积为2*3 = 6。此时栈顶为元素1在数组中的位置1
12. 再将1出栈,计算出面积为1
因此我们可以看出,最大的面积为10。以上就是在O(n)时间复杂度内完成了寻找矩形最大面积的任务。
代码如下:
class Solution { public: int largestRectangleArea(vector<int>& height) { stack<int> st; height.push_back(0); const int len = height.size(); int i =0, sum = 0; while(i < len) { if(st.empty() || height[i] > height[st.top()]) { st.push(i); i++; } else { int top = st.top(); st.pop(); sum = max(sum, height[top] * (st.empty()?i:(i-st.top()-1))); } } return sum; } };参考:http://www.geeksforgeeks.org/largest-rectangle-under-histogram/
http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html