「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战」
前言
力扣第八十四题 柱状图中最大的矩形 如下所示:
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
输入: heights = [2,1,5,6,2,3]
输出: 10
解释: 最大的矩形为图中红色区域,面积为 10
示例 2:
输入: heights = [2,4]
输出: 4
一、思路
题目的意思很简单,就是找到柱状图中最大的矩形面积
这一题最简单就是直接暴力求解了,因为在柱状图中每一个高都有一个对应的面积,只需要将以 heights[i]作为高的矩形面积都计算出来后,取一个最大值即可
我们以 heights = [2,1,5,6,2,3] 举个例子,下图就是以 heights[4] 作为高的矩形面积,它的面积为 2 x 4 = 8
我们发现以 height[i] 作为高的矩形有这个规律:左边界的高度不小于 heights[i],右边界的高度也不小于 heights[i]
利用这个规律我们可以解决这题了,大致的步骤如下所示:
- 找到以
height[i]作为高的的矩形的左右边界 - 计算出每一个矩形的面积,取其中的最大值
而求
heights[i]的左右边界,我们可以使用单调栈,保持栈顶始终存储最靠近的最小值
图解算法(单调栈)
此处以从左到右,求以 heights[i] 作为高的左边界。我们在栈中只存储元素的下标,因为高度可以通过下标来找到
注:为了贴近实际情况,我们的左右边界区间使用的闭合的,即
[i, j]。如[0, 0]表示左右边界都为下标0
- 我们知道第一个元素的左边界一定是子集,所以栈顶初始为
0,首元素的左边界也为0
- 从第二个元素开始遍历,此时栈顶下标对应的高度
height[0] > 1故出栈,再更新左边界,最后将当前的下标入栈
- 遍历到第三个元素,此时栈顶下标对应的高度
height[1] < 5不出栈,更新左边界,最后将当前的下标入栈
- 遍历到第四个元素,此时栈顶下标对应的高度
height[2] < 6不出栈,更新左边界,最后将当前的下标入栈
- 遍历到第五个元素,此时栈顶下标对应的高度
height[3] > 2出栈,直到栈顶下标对应的高度小于2,再更新左边界,最后将当前的下标入栈
- 遍历到第六个元素,此时栈顶下标对应的高度
height[4] < 3不出栈,更新左边界,最后将当前的下标入栈
- 至此就完成了每个高度的左边界寻找了,右边界也是同样的道理。
二、实现
实现代码
实现代码与思路中保持一致
/**
* 单调栈
*/
public int largestRectangleArea(int[] heights) {
int ret = 0;
int len = heights.length;
int[] left = new int[len];
int[] right = new int[len];
// 找到以 heights[i] 作为高度的左边界,栈中存储下标
Deque<Integer> stack = new ArrayDeque<>();
stack.push(0);
left[0] = 0;
for (int i=1; i<len; i++){
while (!stack.isEmpty() && heights[stack.peek()] >= heights[i] ) {
stack.pop(); // 只要栈中下标对应的高度大,就一直出栈
}
if (stack.isEmpty()) { // 如果栈为空,说明左边界是第一个元素
left[i] = 0;
} else {
left[i] = stack.peek() + 1;
}
stack.push(i);
}
stack.clear();
stack.push(len-1);
right[len-1] = len-1;
// 找到以 heights[i] 作为高度的右边界,栈中存储下标
for (int i=len-1; i>-1; i--) {
while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
stack.pop();
}
if (stack.isEmpty()) { // 如果栈为空,说明左边界就是自身
right[i] = len-1;
} else {
right[i] = stack.peek() - 1;
}
stack.push(i);
}
// 计算面积
for (int i=0; i<len; i++) {
ret = Math.max(ret, (right[i] - left[i] + 1) * heights[i]);
}
return ret;
}
测试代码
public static void main(String[] args) {
int[] heights = {2, 1, 5, 6, 2, 3};
new Number84().largestRectangleArea(heights);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~