Leetcode 84.柱状图中最大的矩形
题目描述:
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3] 输出: 10
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram
单调栈:
我们可以看到,直方图矩形面积要最大的话,需要尽可能的使得连续的矩形多,并且最低一块的高度要高。有点像木桶原理一样,总是最低的那块板子决定桶的装水量。
那么既然需要用单调栈来做,首先要考虑到底用递增栈,还是用递减栈来做。我们想啊,递增栈是维护递增的顺序,当遇到小于栈顶元素的数就开始处理,而递减栈正好相反,维护递减的顺序,当遇到大于栈顶元素的数开始处理。那么根据这道题的特点,我们需要按从高板子到低板子的顺序处理,先处理最高的板子,宽度为1,然后再处理旁边矮一些的板子,此时长度为2,因为之前的高板子可组成矮板子的矩形 ,因此我们需要一个递增栈,当遇到大的数字直接进栈,而当遇到小于栈顶元素的数字时,就要取出栈顶元素进行处理了,那取出的顺序就是从高板子到矮板子了,于是乎遇到的较小的数字只是一个触发,表示现在需要开始计算矩形面积了。
为了使得最后一块板子也被处理,这里用了个小 trick,在高度数组最后面加上一个0,这样原先的最后一个板子也可以被处理了。单调栈中不能放高度,而是需要放坐标。由于我们先取出栈中最高的板子,那么就可以先算出长度为1的矩形面积了,然后再取下一个板子,此时根据矮板子的高度算长度为2的矩形面积,以此类推,知道数字大于栈顶元素为止,再次进栈。
class Solution {
public int largestRectangleArea(int[] heights) {
int res=0;
//扩展数组使最后一位为0
int[] height=Arrays.copyOf(heights,heights.length+1);
height[height.length-1]=0;
LinkedList<Integer> s=new LinkedList<>();
for (int i=0;i<height.length;i++){
//如果不递增,触发弹栈
while(!s.isEmpty()&&height[i]<=height[s.peek()]){
int h=height[s.pop()];//取栈顶位置高度
int w=s.isEmpty()?i:i-s.peek()-1;//求当前要计算的宽度
//i-s.peek()-1 意为弹栈的过程中,遍历到的位置所能达到的最大面积矩形的宽度一定是和当前下标I之间的距离
//当栈为空时,要考虑之前弹出的位置。这些之前弹出的位置的高度一定比当前栈底高,所有宽度直接取当前下标I。此情况的例子为[2,1,2]
res=Math.max(res,w*h);//更新最大值
}
s.push(i);
}
return res;
}
}