84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
这道题有多种解法,这里主要介绍用单调栈的解法。
分析这道题:常见思路就是遍历,看每个柱子能参与围成的最大矩形面积,即找到当前柱子左右大于等于它的柱子数,即大于等于当前柱子的左右边界:
- 面 积 = ( 右 边 界 − 左 边 界 ) ∗ 当 前 柱 子 高 度 面积=(右边界-左边界)*当前柱子高度 面积=(右边界−左边界)∗当前柱子高度。
那问题是如何确定大于等于当前柱子的左右边界呢?
根据这个思路,单调栈十分适合这个思路。
- 1.单调栈分为递增或递减栈
- 2.如果是递增栈,如果栈顶元素小于等于新元素,直接插入;如果栈顶元素大于新元素i,则执行出栈操作(通过在末尾添加0,保证每个元素都会进行入栈出栈),出栈时会计算当前柱子构建的面积,面积=(右边界-左边界)*当前柱子高度,右边界为i,左边界为栈顶元素前一个元素。
例如[2,1,5,6,2,3],末尾添加元素0,[2,1,5,6,2,3,0]栈的变化如下
[0] 元素0入栈
[] 由于2>1,所以执行出栈并计算面积 2 ∗ ( 1 − 0 ) 2*(1-0) 2∗(1−0),然后元素1的索引入栈
[1,2]元素5的索引入栈
[1,2,3]元素6的索引入栈
[1,2]由于6>2,所以6出栈并计算面积;由于5大于2,所以5继续出栈并计算面积
[1,4]
[1,4,5]
[1,4]这里遍历到我们增加的元素0,所以执行出栈,这样所有元素执行出栈。
注意:
- 如果是相邻的相同元素,实际以前面的元素面积为准,不过最后取的都是最大值,这里没有影响。
- 当计算面积时当前为空栈,表示前面的元素都大于栈顶元素,所以计算面积时左边界从索引0开始
- 出栈的截止条件是栈顶元素大于等于遍历到的元素
代码如下
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
heights.push_back(0);
int maxval = 0;
stack<int> stk;
for(int i=0;i<heights.size();i++){
while(!stk.empty()&&heights[i]<heights[stk.top()]){
int top = stk.top();
stk.pop();
maxval = max(maxval,heights[top]*(stk.empty()? i: i-stk.top()-1));
}
stk.push(i);
}
return maxval;
}
};
int main(){
vector<int> heights = {2,1,3,4,5};
int res = Solution().largestRectangleArea(heights);
cout<<res<<endl;
}
其实我觉得最精髓的是出栈的控制,执行流程已经看懂,后续慢慢体会~