题目描述
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
代码1(超时了,但是算法思路是对的):
public class Solution84 {
public static int largestRectangleArea(int[] heights) {
int maxElem = 0;
for (int height : heights) {
if (height >= maxElem){
maxElem = height;
}
}
int[] cutHeight = new int[heights.length];
int area_max = 0;
int index = 0;
for (int i = 0;i<maxElem;i++){
int len = 0;
int min = Integer.MAX_VALUE;
for (int j = 0;j<heights.length;j++){
cutHeight[j] = (heights[j]-(i))<0?0:heights[j]-(i);
if ( cutHeight[j]== 0){
len = 0;
min = Integer.MAX_VALUE;
}else {
len++;
if (cutHeight[j]<=min){
min = cutHeight[j];
index = j;
}
int tempArea = (len)*heights[index];
if (tempArea>=area_max){
area_max = tempArea;
}
}
}
}
return area_max;
}
}
代码2(单调递增栈):
class Solution {
public int largestRectangleArea(int[] heights) {
// 初始化最终结果为0
int res = 0;
Stack<Integer> stack = new Stack<>();
// 将给定的原数组左右各添加一个元素0
int[] newHeights = new int[heights.length + 2];
newHeights[0] = 0;
newHeights[newHeights.length-1] = 0;
for (int i = 1; i < heights.length + 1; i++) {
newHeights[i] = heights[i - 1];
}
// 开始遍历
for (int i = 0; i < newHeights.length; i++) {
// 如果栈不为空且当前考察的元素值小于栈顶元素值,
// 则表示以栈顶元素值为高的矩形面积可以确定
while (!stack.isEmpty() && newHeights[i] < newHeights[stack.peek()]) {
// 弹出栈顶元素
int cur = stack.pop();
// 获取栈顶元素对应的高
int curHeight = newHeights[cur];
// 栈顶元素弹出后,新的栈顶元素就是其左侧边界
int leftIndex = stack.peek();
// 右侧边界是当前考察的索引
int rightIndex = i;
// 计算矩形宽度
int curWidth = rightIndex - leftIndex - 1;
// 计算面积
res = Math.max(res, curWidth * curHeight);
}
// 当前考察索引入栈
stack.push(i);
}
return res;
}
}
分析
代码一所有的方法比较奇特,是一行一行减1之后,寻找连续非零的长度,然后再非零中找出最小的下标值,然后进行求解,由于代码一的代码比较复杂,以及变量也比较多,所以时间复杂度超了,但是可以参考一下本方法的思想。
代码二使用单调递增栈进行求解,和之前的接雨水那题比较相似,但是那题是单调递减栈,本题是单调递增栈,就是当前元素如果小于栈顶元素,就将栈顶元素出栈,知道遇到栈顶元素小于当前元素即可。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/largest-rectangle-in-histogram/