给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
来源:力扣(LeetCode)
首先肯定暴力啊,思想:矩形有长宽啊,暴力枚举。。。wa在了最后一个样例(样例个数超1W)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int ans=0;
int wid=0;
int tep=0;
for(auto hei:heights){//矩形长
for(auto cn:heights){
if(hei<=cn){
wid++;//矩形宽
tep=hei*wid;
}else{
ans=max(ans,tep);
tep=0;
wid=0;
}
}
ans=max(ans,tep);
tep=0;
wid=0;
}
return ans;
}
};
分治法,
1.确定了最矮柱子以后,矩形的宽尽可能往两边延伸。
2.在最矮柱子左边的最大面积矩形(子问题)。
3.在最矮柱子右边的最大面积矩形(子问题)。
class Solution {
public:
int calculate(vector<int>&heights,int start,int end){
if(start>end) return 0;
int mini=start;
for(int i=start;i<=end;i++){
if(heights[mini]>heights[i]){
mini=i;
}
}
return max(heights[mini]*(end-start+1),max(calculate(heights,start,mini-1),calculate(heights,mini+1,end)));
}
int largestRectangleArea(vector<int>& heights) {
return calculate(heights,0,heights.size()-1);
}
};
当时还用minH=0x3f3f3f3f,没想到有个样例是int的最大范围,这个说明一定要谨慎。平均O(nlogn),最坏O(n^2).
看了一下大佬的思想。
以第i根柱子为最矮柱子所能延伸的最大面积。具体就是找出第i根柱子左边第一个小于heights【i】的下标left_i;右边也是,找出第一个小于heights【i】的下标right_i,则面积是heights【i】*(right_i - left_i -1)
剩下的就是如何高效的找出这两个数组了。
1.如果heights【i-1】>=heights【i】,那么问题转化为找出第i-1柱子左边的柱子。
//遍历左边
for(i from 0 to heights.size(){
int tmp=i-1;
while(heights[i-1]>=heights[i]) tmp=left_i[tmp];
left_i[i]=tmp;
)
//在添加一些边界即可。
总体代码
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
if(heights.empty()) return 0;//力扣上数组长度可能为0
int size=heights.size();
int left_i[size+1];
int right_i[size+1];
left_i[0]=-1;
right_i[size-1]=size;
for(int i=1;i<size;i++){
int tmp=i-1;
while(tmp>=0&&heights[tmp]>=heights[i]) tmp=left_i[tmp];
left_i[i]=tmp;
}
for(int i=size-2;i>=0;i--){
int tmp=i+1;
while(tmp<size&&heights[tmp]>=heights[i]) tmp=right_i[tmp];
right_i[i]=tmp;
}
int ans=0;
for(int i=0;i<size;i++){
ans=max(ans,heights[i]*(right_i[i]-left_i[i]-1));
}
return ans;
}
};
- 单调栈
栈里面的元素是递增的。保存的是矩形的下标。
当柱子的高度递增时,入栈柱子的下标。
当出现柱子(i)的高度小于栈顶时(右边第一个高度小于他的矩形),可以套公式计算了。
right_i=i, left_i =弹出栈之后的栈顶(栈里面是递增的,弹出栈之后,找到了左边第一个小于他的矩形),高度=heights[ 当前栈顶]。
遍历完了之后,栈里面可能还有元素。这时要注意 right_i 始终等于= heights.size()了。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int>st;
st.push(-1);
int size=heights.size();
int ans=0;
for(int i=0;i<size;i++){
while(st.top()!=-1&&heights[i]<heights[st.top()]){
int top=st.top();
st.pop();
ans=max(ans,heights[top]*(i-1-st.top()));
}
st.push(i);
}
while(st.top()!=-1){
int top=st.top();
st.pop();
ans=max(ans,heights[top]*(size-1-st.top()));
}
return ans;
}
};
不得不说这个-1和size真是太妙了!!