题目描述如下:
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
.
======================================================
这题刚开始脑筋转不过来,老实去想什么长跟宽的关系啊什么的,只能想到o(n2)的办法。
后来在网上看别人提示: 对一个最大面积它的高必定是某一个柱的柱高,因此我们可以枚举每一个柱高然后向左右扩展找最长的长度,扩展的条件是两边的柱高必须高于等于它。
我们使用 leftest[ ] 和 rightest[ ]来保存每个柱子最左和最右能扩展到的下标,于是对每个柱子,以其高能扩展的最大面积为: height[ i ]* ( rightest [i ] - leftest [i ] +1 ),最后返回最大的那个就是了。
简单的对每个i 向左右扩展更新 leftest 和 rightest 是O(n2)的,有没有办法将其降低到 o(n)呢? 当然是有的:那就是借助单调队列!
首先我们这么想,对一个i,其高度为height[i],i-1 的leftest[i-1]已经计算过了,如果height[i] 比左边高,肯定不能向左边扩展了,leftest[i] = i,如果比左边低,我们能直接说leftest[i] = leftest[i -1]吗? 当然是不行的,比如我们举个反例:
height : 2 3 1 : 明显leftest[0] =0 ,leftest[1]=1,此时我们发现 1<3,那我们可以得到 leftest[2]=leftest[1]=1吗?明显不是,还可以向左扩展的。
所以我们必须要找到 i 左边最远的比它大的元素,然后leftest等于它,这个过程可以借助单调队列,因为单调队列所有元素最多只进一次栈出一次栈,所以分摊复杂度是o(n)的!
单调队列我就不介绍了,各位可以在网上找些浅显的资料了解一下!
代码如下:
int largestRectangleArea(vector<int>& hei) { if(hei.empty()) return 0; int sz=hei.size(); vector<int> leftest(sz,0); vector<int> rightest(sz,0); vector<int> lQueue; vector<int> lIndex; vector<int> rQueue; vector<int> rIndex; int i; for(i=0;i<sz;i++) { if (lQueue.empty()||lQueue.back()<hei[i]) { leftest[i]=i; lQueue.push_back(hei[i]); lIndex.push_back(i); } else { int tmp=i; while(!lQueue.empty()&&lQueue.back()>=hei[i]) { tmp=leftest[lIndex.back()]; lQueue.pop_back(); lIndex.pop_back(); } leftest[i]=tmp; lQueue.push_back(hei[i]); lIndex.push_back(i); } } for(i=sz-1;i>=0;i--) { if(rQueue.empty()||rQueue.back()<hei[i]) { rightest[i]=i; rQueue.push_back(hei[i]); rIndex.push_back(i); } else { int tmp=i; while(!rQueue.empty()&&rQueue.back()>=hei[i]) { tmp=rightest[rIndex.back()]; rQueue.pop_back(); rIndex.pop_back(); } rightest[i]=tmp; rQueue.push_back(hei[i]); rIndex.push_back(i); } } int ans=INT_MIN; for(i=0;i<sz;i++) { ans=max(ans,hei[i]*(rightest[i]-leftest[i]+1)); } return ans; }