题目描述:
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
int largestRectangleArea(int* heights, int heightsSize){
}
思路引导:矩形面积=高 X 宽
很明显:我们大致有两个思路,一是以高为基准,找最大宽度,然后依次比较面积,二是以宽度为基准,找最小高度,然后依次比较面积
我们先进行两个思路的基本实现
1.以高度为基准,找宽度
int largestRectangleArea(int* heights, int heightsSize){
int mid=0;
int ans=0;
for(mid=0;mid<heightsSize;mid++)
{
int left=mid;
int right=mid;
while(left-1>=0&&heights[left-1]>=heights[mid])
left--;
while(right+1<heightsSize&&heights[right+1]>=heights[mid])
right++;
ans=fmax(ans,heights[mid]*(right-left+1));
}
return ans;
}
2.以宽度为基准,找高度
int largestRectangleArea(int* heights, int heightsSize){
int max=0;
for(int i=0;i<heightsSize;i++)
if(max<heights[i])
max=heights[i];
for(int j=1;j<heightsSize;j++)
{
int minheight=heights[j];
for(int i=j-1;i>=0;i--)
{
minheight=fmin(heights[i],minheight);
max=fmax(max,minheight*(j-i+1));
}
}
return max;
}
但很遗憾:两种方法的时间复杂度均为O(n^2),超出时间限制
那么我们如何优化时间复杂度呢?将时间复杂度变为O(n)-----只遍历一遍数组
我们观察上面两种写法和思路,会发现根据高来找宽的限制条件更加有"可操作性",而根据宽度来找高枚举的情况更多(即连续不同的宽度可能有多个相同的高),会导致不必要的计算,也就是说根据高来找宽,在优先级上已经高于根据宽来找高
那么根据高来找宽的过程,即左右边界的确定,如何通过一次遍历得到?
我们再来看看边界是如何确定的,假设我们找以下标为i的柱子高度为矩形的左右边界,那么我们只要找到比heights[i]小的最靠近i的左右柱子,就能找到左右边界,而问题的关键和答案就在标红的那句话上------单调栈
---------------------------------------------------------------------------------------------------------------------------------
什么是单调栈?
浅浅的理解一下就是栈中元素按照某种单调性存储,即符合单调性就将元素进栈,反之将栈中"阻止"该元素进栈的元素去掉,然后将元素进栈,使得栈上的元素始终保持单调性
其实,仔细想一想之前我发的表达式求值问题也是运用了单调栈的性质(符号的优先级)
---------------------------------------------------------------------------------------------------------------------------------
int largestRectangleArea(int* heights, int heightsSize){
int left[heightsSize];
int right[heightsSize];
int stack[heightsSize];//建立栈
int top=-1;//栈为空
for(int i=0;i<heightsSize;i++)//求左边界
{
while(top!=-1&&heights[stack[top]]>=heights[i])//栈要满足严格单调增且不为空
top--;
left[i]=(top==-1?-1:stack[top]);
stack[++top]=i;
}
top=-1;
for(int i=heightsSize-1;i>=0;i--)//求右边界
{
while(top!=-1&&heights[stack[top]]>=heights[i])
top--;
right[i]=(top==-1?heightsSize:stack[top]);
stack[++top]=i;
}
int ans=0;
for(int i=0;i<heightsSize;i++)//计算面积找出最大值
ans=fmax(ans,(right[i]-left[i]-1)*heights[i]);
return ans;
}