链接:http://leetcode.com/onlinejudge#question_84
原题:
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
.
思路:
我是用二分法做的。
1. 选择中间一个元素,那么向两边遍历,找到最大矩形,复杂度为O(N);
2.不选择中间一个元素,那么递归找左右两支的最大矩形
所以总的复杂度为O(nlogn)
在网上搜了一把,发现有一个O(N)的方法,额外用一个stack记录,挺巧妙。
我这种脑子是想不出来的,呵呵。
代码:
class Solution { public: int largestRectangleArea(vector<int> &height) { // Start typing your C/C++ solution below // DO NOT write int main() function return maxArea(height, 0, height.size()); } private: int maxArea(const vector<int> &height, int left, int right) { if (right <= left) return 0; int mid = (left + right) / 2; int curMin = height[mid]; int curMaxArea = 0; int curLeft = mid, curRight = mid; while (curLeft >= left && curRight < right) { for (; curLeft >= left; curLeft--) if (height[curLeft] < curMin) break; for (; curRight < right; curRight++) if (height[curRight] < curMin) break; int temp = (curRight - curLeft - 1) * curMin; if (curMaxArea < temp) curMaxArea = temp; if (curLeft < left || curRight >= right) break; if (height[curLeft] >= height[curRight]) curMin = height[curLeft]; else curMin = height[curRight]; } while (curLeft >= left) { curMin = height[curLeft]; for (; curLeft >= left; curLeft--) if (height[curLeft] < curMin) break; int temp = (curRight - curLeft - 1) * curMin; if (curMaxArea < temp) curMaxArea = temp; } while (curRight < right) { curMin = height[curRight]; for (; curRight < right; curRight++) if (height[curRight] < curMin) break; int temp = (curRight - curLeft - 1) * curMin; if (curMaxArea < temp) curMaxArea = temp; } int leftMax = maxArea(height, left, mid); if (curMaxArea < leftMax) curMaxArea = leftMax; int rightMax = maxArea(height, mid+1, right); if (curMaxArea < rightMax) curMaxArea = rightMax; return curMaxArea; } };
再次做这道题目,就试了一下O(N)的方法,
如果暴力,就是枚举所有柱子,以它为高,先左右两边分别找比它小的边界,然后算面积,这样是O(N^2)。
但是有一种数据结构可以在O(N)时间里面找到边界(所有元素),叫increasing stack,单调递增子段。
具体作法是:如果栈顶元素值不大于当前值,就把当前值push到栈里面;如果大于当前值,那么凡是栈里面
比当前值大的元素,都是以当前值为右边界,做边界当然是栈里比它前面一个。So nice。
P.S. 不要忘了最后清空栈。
代码:
class Solution { public: int largestRectangleArea(vector<int> &height) { // Start typing your C/C++ solution below // DO NOT write int main() function if (height.size() == 0) return 0; stack<int> indexStack; indexStack.push(-1); indexStack.push(0); int maxArea = 0; for (int i=1; i<height.size(); i++) { int cur = height[i]; while (indexStack.size()>1 && cur < height[indexStack.top()]) { int maxHeight = height[indexStack.top()]; indexStack.pop(); int curArea = maxHeight * (i - indexStack.top() - 1); if (curArea > maxArea) maxArea = curArea; } indexStack.push(i); } while (indexStack.size() > 1) { int maxHeight = height[indexStack.top()]; indexStack.pop(); int curArea = maxHeight * (height.size() - indexStack.top() - 1); if (curArea > maxArea) maxArea = curArea; } return maxArea; } };