[LeetCode]84. 柱状图中最大的矩形(java实现)单调栈
1. 题目
2. 读题(需要重点注意的东西)
思路(单调栈):
单调栈能解决的问题: 找这个序列中每个数左边(或右边)离他最近的比他小的数下标是多少
本题的本质是找每一个数左边第一个比它小的数left[i]
和右边第一个比他小的数right[i]
,(right[i] - left[i] - 1) * heights[i]
就是当前列的最大的矩形面积
解法:
-
维护一个left栈,找到每个数左边第一个比它小的数,存储它的下标
-
维护一个right栈,找到每个数右边第一个比他小的数,存储它的下标
-
用 (right[i] - left[i] - 1) * heights[i] 就是当前柱子最大的矩形面积
注: 单调栈的思想见[AcWing]830. 单调栈(C++实现)单调栈模板题
3. 解法
---------------------------------------------------解法---------------------------------------------------
class Solution {
public int largestRectangleArea(int[] h) {
int n = h.length;
int[] left = new int[n + 10];
int[] right = new int[n + 10];
// 定义一个单调栈,用数组实现
int[] stk = new int[n + 10];
// 单调栈索引
int tt = 0;
// 从左往右扫描每个矩形左边的第一个比它小的数的下标
for(int i = 0;i < n;i++){
while(tt != 0 && h[stk[tt]] >= h[i]) tt--;
if(tt == 0) left[i] = -1;
else left[i] = stk[tt];
stk[++tt] = i;
}
// 从右往左扫描每个矩形右边的第一个比它小的数的下标
// 索引归0
tt = 0;
for(int i = n - 1;i >= 0;i--){
while(tt != 0 && h[stk[tt]] >= h[i]) tt--;
if(tt == 0) right[i] = n;
else right[i] = stk[tt];
stk[++tt] = i;
}
// 扫描一遍数组,求出答案
int res = 0;
for(int i = 0;i < n;i++)
res = Math.max(res,(right[i] - left[i] - 1) * h[i]);
return res;
}
}
可能存在的问题:
4. 可能有帮助的前置习题
5. 所用到的数据结构与算法思想
6. 总结
本题主要有两个难点:
- 要知道本题的本质是找每一个数左边第一个比它小的数
left[i]
和右边第一个比他小的数right[i]
,(right[i] - left[i] - 1) * heights[i]
就是当前列的最大的矩形面积 - 要会使用单调栈找左右的第一个比它小的位置在哪(要会使用单调栈):
以找左边第一个比当前列小的数的位置为例,当遍历到当前列时,如果栈顶元素大于当前元素,栈顶元素出栈,直到栈顶元素小于当前元素,此时的栈顶元素就是第一个比它小的元素,如果栈找空了,则说明没有比它小的元素,将其置为-1,然后将当前元素进栈。
此外,可以直接使用栈Stack,也可以使用数组模拟栈