#84. Largest Rectangle in Histogram(求矩形最大面积)
题目来源:
https://leetcode.com/problems/largest-rectangle-in-histogram/description/
题意分析:
给一个正整数列表,每个数字x在直方图上表示宽度为1的矩形的高度,求直方图中的最大矩形。
题目思路:
最大矩形的高是由组成矩形的小矩形的最小高度决定的,对于列表[x1,x2,x3,...],每个x都有可能是最大矩形的最小高度,对于这个x,高度确定了,只要求出最大宽度就可以求解。所以问题可以转化为求以x为轴,左右边第一个比x小的值的下标。然后最大矩形就是所有x求出的矩形的最大项。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int left,right;
int res=0;
for (int i=0; i<heights.size(); i++){
left=i;
right=i;
while(left>=0&&heights[left]>=heights[i])
left--;
while(right<heights.size()&&heights[right]>=heights[i])
right++;
res=res>(right-left+1)*heights[i]?res:(right-left-1)*heights[i];
}
return res;
}
};
上述解法的时间复杂度是O(n^2),提交后超时了,那么只能想O(n)或者O(nlogn)的算法了。我们会发现大部分的时间都用在了求left跟right上,我们可以用一个栈s来优化这一过程。
求right的思路如下,s保存的是没有求到right值的值的列表下标,开始为空。从左到右遍历列表,如果s空或者heights[s.top()]<=heights[i],即当前的高度不小于s栈顶高度的话,把当前高度的下标推进s。如果heights[s.top()]>heights[i],当前的高度比s栈顶高度要小,那么i就是前面那些比heights[i]大且没求到right值的值的right值,弹出s中所有比heights[i]大的值并把right值设为i,然后再把i推进s。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
// heights.push_back(0);
vector<int> left(heights.size(),-1);
vector<int> right(heights.size(),heights.size());
stack<int> s;
// s.push(0);
for (int i=0; i<heights.size(); i++){
cout<<i<<endl;
while (s.size()>0&&heights[i]<heights[s.top()]){
right[s.top()]=i;
s.pop();
}
s.push(i);
}
s=stack<int>();
//s.push(0);
for (int i=heights.size()-1; i>=0; i--){
while (s.size()>0&&heights[i]<heights[s.top()]){
left[s.top()]=i;
s.pop();
}
s.push(i);
}
// for(int i=0; i<heights.size(); i++)
// cout<<left[i]<<" "<<right[i]<<endl;
int res=0;
for(int i=0; i<heights.size(); i++){
res=res>(right[i]-left[i]-1)*heights[i]?res:(right[i]-left[i]-1)*heights[i];
}
return res;
}
};
这一解法时间复杂度为O(n),因为对于每个i,right[i],left[i]只计算了一次。提交后A了,但时间长到看不到百分号。
我们观察栈s,如果把它里面的坐标i映射到heights[i],那么它是有序的,栈底到栈顶heights由小到大,而且在不断push,pop的过程中依然能保持,那么我们在求到栈顶元素的right值时,如果把栈顶元素pop出来,剩下的栈顶元素就是就是左边第一个heights比开始栈顶元素的heights小的下标,那么我们在求right的时候就可以求出left已经矩形面积了。
class Solution{
public:
int largestRectangleArea(vector<int>& heights) {
int len = heights.size();
// heights.push_back(0);
stack<int> s;
// s.push(0);
int ans = 0;
for(int i = 0; i < len; i ++)
{
while(! s.empty() && heights[i] < heights[s.top()])
{
int index = s.top();
s.pop();
ans = max(ans, heights[index]*(i-1-(s.empty()?-1:s.top())));
};
s.push(i);
};
while(s.size()>0){
int index = s.top();
s.pop();
ans = max(ans, heights[index]*(len-1-(s.empty()?-1:s.top())));
}
return ans;
}
};