84. 柱状图中最大的矩形/C++

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

84. 柱状图中最大的矩形/C++_第1张图片

以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。

84. 柱状图中最大的矩形/C++_第2张图片

图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

示例:

输入: [2,1,5,6,2,3]

输出: 10

这道题最好的做法是是使用单调栈,只要遍历一次就可求出最大面积。

一、如何求最大矩形面积

现在我们从头开始讲,如果要求只能遍历一次,那么如何求最大面积?
我想到一个思路,那就是先把能完全包含各个柱状图的矩形的最大面积求出来,然后求出其中最大值即可。以例题来说就是

  • 能完全覆盖第0个柱子的最大矩形
    84. 柱状图中最大的矩形/C++_第3张图片

  • 能完全覆盖第1个柱子的最大矩形
    84. 柱状图中最大的矩形/C++_第4张图片

  • 能完全覆盖第2个柱子的最大矩形
    84. 柱状图中最大的矩形/C++_第5张图片

  • 能完全覆盖第3个柱子的最大矩形
    84. 柱状图中最大的矩形/C++_第6张图片

  • 能完全覆盖第4个柱子的最大矩形
    84. 柱状图中最大的矩形/C++_第7张图片

  • 能完全覆盖第5个柱子的最大矩形
    84. 柱状图中最大的矩形/C++_第8张图片
    如此这般,就能够覆盖所有分支而又不遗漏,将这6个矩形的面积比较下就知道最大面积了。

二、如何求以某个柱子为高的最大矩形

84. 柱状图中最大的矩形/C++_第9张图片
我们就以例题中第4个,高为2的柱子举例好了。
矩形的面积=高*宽。
我们很高兴的发现,在这个分支情况下,我们已经知道高为2了,那么宽度如何求呢?
通过观察,我们发现矩形的左边沿是左边第一个高比2小的柱子,右边沿是右边第一个高比2小的柱子(将高为3的柱子的右面看作还有一个高为0的柱子)
如此它的宽度是6-(1+1)=4

这时可能你已经一头雾水了,6是啥?1是啥?为什么要加1?
如果你这么问,我打赌你肯定是如下图这么想的。
84. 柱状图中最大的矩形/C++_第10张图片
如果你将柱子的左下角对应序号的话,或许会好一些。
84. 柱状图中最大的矩形/C++_第11张图片
我们说了矩形的左边沿是第1个柱子的右边,那可不就是(1+1)了吗?
矩形右边沿是第6个柱子的左边,直接就是6.
宽度自然就是6-(1+1)=4了。

注意:基于各个高度的最大矩形是在出栈的时候计算的,因此必须要让所有高度都出栈。这里是利用单调栈的性质让其全部出栈,即在原始数组后添一个0.

三、如何寻找左右边沿

我们已经说了,左边沿是左边第一小与本柱子高的柱子的右边,右边沿也是同理。
这正好可以用单调栈。
当第i个柱子进栈时,如果栈顶柱子(此处记作柱子A)的高度低于或等于第i个柱子,则第i个柱子进栈;
如果高于第i个柱子,则出栈,并计算以柱子A为高的矩形最大面积。

  • 高度:就是柱子A的高度
  • 右边沿:正好是i(由于单调栈的性质,第i个柱子就是右边第一个矮于A的柱子)
  • 左边沿:单调栈中紧邻A的柱子。(如果A已经出栈,那么左边沿就是A出栈后的栈顶)而且是该柱子的右边,所以要+1.

因此,完全覆盖第index个柱子的最大矩形的面积如下(stk是单调栈)

maxArea=heights[index]*(i - (stk.top() +1))

还有一种情况。当A出栈后,单调栈为空时,那就是说明,A的左边没有比它矮的。左边沿就可以到0.

maxArea=heights[index]*(stk.empty()? i:(i - stk.top() -1)))

四、代码

int largestRectangleArea(vector<int>& heights) {
     heights.push_back(0);
     stack<int> stk;
     int maxArea = 0;
     for(int i = 0;i<heights.size();i++)
     {
         while(!stk.empty() && heights[i]<heights[stk.top()])
         {
             int top= stk.top();
             stk.pop();
             maxArea = max(maxArea,heights[top]*(stk.empty()? i:(i - stk.top() -1)));
         }
         stk.push(i);
     }
     return maxArea;
}

第一次这么认真写这种东西,请大家多多支持,评论,点赞,收藏。

你可能感兴趣的:(栈,LeetCode/C++)