题目:
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]
。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10
个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
题目分析 :
如果输入为非递减序列,例如输入为{1, 1, 2, 2, 2, 3},那么矩形图为:
那么最大面积就是max(1 * 6, 1 * 5, 2 * 4, 2 * 3, 2 * 2, 3 * 1 )
我们的目的就是构建一个这样的序列,这样就可以很方便的求解,我们利用栈来构建这样一个非递减序列
输入: [2,1,5,6,2,3]
入栈原则:栈为空或者栈顶的元素小于正在处理的数, 如果当前栈顶元素大于正在处理的数,栈顶元素弹出(不停的弹出,直到栈顶元素小于正处理数),再入栈; 最大面积初始值为0
思路如下(编写代码不方便)
step1: 处理数字2,由于栈为空, ---------------栈内元素为{ 2 },面积为0
step2:处理数字1, 当前栈顶元素2大于1, 弹出栈顶元素2,由于把2弹出了,所以我们最后的栈内没有这个元素,所以我们现在就得计算以2为高的最大矩形面积,高度为2, 长度为1(因为2 的后面就是1,1比2小),面积为 2,更新面积;1入栈,由于弹出了一个, 所以入栈两个1 ------------------------栈内元素为{1, 1},面积为2
step3:处理数字5,当前栈顶元素为1, 小于5,5入栈; ---------------------------栈内元素为{1, 1, 5}, 面积为2
step4:处理数字6,当前栈顶元素为5, 小于6, 6入栈, -----------------------------栈内元素为{1, 1, 5, 6},面积为2
step5:处理数字2. 当前栈顶元素为6, 大于2,把6弹出,同理处理以6为高的矩形面积,高度为6, 长度为1(6前面的和后面的矩形高度都比6小), 面积为6,更新面积; 栈内元素{1, 1, 5} ,栈顶元素为5,仍然大于2,把5弹出, 处理以5为高的的矩形面积,高为5, 长度为2(5前面的一定比它小,之前弹出了一个6, ), 面积为 5 * 2 = 10, 更新面积,2 入栈,由于弹出两个数,入栈3个2 --------------------------------------------栈内元素为{1, 1, 2, 2, 2}, 面积为 10
step6:处理数字3,当前栈顶元素为2,小于3, 入栈 , -----------------------------栈内元素为{1, 1, 2, 2, 2, 3}, 面积为 10
step7:现在我们得到了前面提到的非递减序列,可以计算面积了
我们可以看到上面的栈内有很多冗余数据,入栈操作麻烦;为了方便编程我们使用数组的下标进行入栈,上面例子最后的栈内元素就是{1, 4, 5}, heights[1] = 1, 其中有 1 - 0 + 1 = 2个1;heights[4] = 2, 其中有 4 - 1 = 3个 2; heights[5] = 3, 其中有5 - 4 = 1个3,(第一个元素的个数特殊处理),可以说栈{1, 1, 2, 2, 2, 3}, 与栈 {1, 4, 5}信息等价,原理介绍完毕,完整代码如下:
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
stack<int> index;
int area = 0;
//数据入栈与出栈处理
for(int i = 0; i < n; i++)
{
if(index.empty() || heights[index.top()] < heights[i])
{
index.push(i);
}
else
{
while(!index.empty() && heights[index.top()] >= heights[i])
{
int tem = heights[index.top()];
index.pop();
int len = 0;
if(index.empty())
{
len = i;
}
else
{
len = i - index.top() - 1;
}
area = max(area, len * tem);
}
index.push(i);
}
}
//整体处理
while(!index.empty())
{
int tem = heights[index.top()];
index.pop();
int len = 0;
if(index.empty())
{
len = n;
}
else
{
len = n - index.top() - 1;
}
area = max(area, len * tem);
}
return area;
}
};