【题目】**84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
【解题思路1】暴力法
【解题思路2】单调栈
遍历到下标4的时候,可以确定高度为6的宽度最多为1,然后也可以确定高度为5的宽度最多为2,先确定了3位置对应高度的宽度,然后确定2位置对应高度的宽度,符合先进后出的规律
- 入栈一个元素高度,表示这个高度还无法确定其宽度
- 出栈一个元素高度,表示可以确定这个高度的宽度了
- 出栈条件,遍历到的元素高度严格小于当前栈顶元素高度,栈顶元素出栈,顺便计算出栈顶元素高度能勾勒出的矩形的宽度和面积
- 矩形宽度 = 当前遍历到的下标 - 出栈以后的新栈顶下标 - 1
可以假象最右边有个高度为0的柱形其小标为6,所小标4对应的高度为2的柱形可以一直扩散到末尾
遇到新栈顶和当前栈顶高度相同的情况,弹出当前的栈顶直接跳过,不计算面积
但也可以不做特殊处理,因为在计算新栈顶的时候会把不准确的结果替换掉
哨兵1可以省去栈非空判断
哨兵2可以保证所有元素都出栈(除了哨兵1这个高度为0的),可以省去遍历完之后再将栈内剩余元素出栈的步骤
class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if(len == 0){
return 0;
}
if(len == 1){
return heights[0];
}
int area = 0;
Stack<Integer> stack = new Stack<>();
for(int i = 0; i < len; i++){
//当栈顶元素高度大于当前遍历到的元素高度
while(!stack.isEmpty() && heights[stack.peek()] > heights[i]){
int height = heights[stack.pop()];
//处理栈顶和新栈顶元素值相同的情况,可以省去这步
while(!stack.isEmpty() && heights[stack.peek()] == height){
stack.pop();
}
int width;
if(stack.isEmpty()){
width = i; //栈空,说明从开头到当前位置都可以构成高度为height的矩形
}else{
width = i - stack.peek() - 1;
}
area = Math.max(area, width * height);
}
stack.push(i);
}
//栈中剩余元素依次出栈,逻辑和上面完全一样
while(!stack.isEmpty()){
int height = heights[stack.pop()];
//处理栈顶和新栈顶元素值相同的情况,可以省去这步
while(!stack.isEmpty() && heights[stack.peek()] == height){
stack.pop();
}
int width;
//注意这里直到len都可以构成height高度的矩形,不受下一个heights[i]约束
if(stack.isEmpty()){
width = len;
}else{
width = len - stack.peek() - 1;
}
area = Math.max(area, width * height);
}
return area;
}
}
设置哨兵精简后的代码
class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if(len == 0){
return 0;
}
if(len == 1){
return heights[0];
}
int area = 0;
int[] newHeights = new int[len + 2];
for(int i = 0; i < len; i++){
newHeights[i + 1] = heights[i];
}
len += 2;
heights = newHeights; //这样写的话,下面的逻辑里面的数组名就不需要更新了
Stack<Integer> stack = new Stack<>();
stack.push(0);
for(int i = 0; i < len; i++){
//当栈顶元素高度大于当前遍历到的元素高度
while(heights[stack.peek()] > heights[i]){
int height = heights[stack.pop()];
int width = i - stack.peek() - 1;
area = Math.max(area, width * height);
}
stack.push(i);
}
return area;
}
}