Skip to content

Commit ab0650b

Browse files
committed
84.柱状图中最大的矩形,单调递增栈
1 parent ab87771 commit ab0650b

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

leetcode_Java/DoneTitle.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
72. 编辑距离
2727
77. 组合
2828
78. 子集
29+
84. 柱状图中最大的矩形
2930
90. 子集 II
3031
93. 复原 IP 地址
3132
94. 二叉树的中序遍历

leetcode_Java/Solution0084.java

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// 84. 柱状图中最大的矩形
2+
3+
4+
/*
5+
暴力:
6+
1、数组扩容,首尾添加哨兵0元素,作为最低点,方便作为任意高度的左右边界
7+
2、遍历柱子高度,对于每一个柱子高度分别向两边扩散,求出当前高度为矩形的最大宽度
8+
3、最大宽度的 左边界是当前柱子向左遍历第一个低于当前柱子高度的位置,右边界是当前柱子向右遍历第一个低于当前柱子高度的位置,左右边界的距离就是最大宽度
9+
4、当前柱子最大面积 = 最大宽度 * 当前柱子高度,比较并保存最大面积
10+
11+
高度: 0 2 1 5 6 2 3 0
12+
索引: 0 1 2 3 4 5 6 7
13+
↑ ↑ ↑
14+
left i right
15+
(right - left - 1) * newHeights[i] = (5-2-1)*5 = 10
16+
*/
17+
class Solution {
18+
public int largestRectangleArea(int[] heights) {
19+
int res = 0;
20+
int n = heights.length;
21+
int[] newHeights = new int[n + 2];
22+
for (int i = 0; i < n; i++) {
23+
newHeights[i + 1] = heights[i];
24+
}
25+
for (int i = 1; i < n + 1; i++) {
26+
int left = i - 1;
27+
while (left > 0 && newHeights[i] <= newHeights[left]) {
28+
left--;
29+
}
30+
int right = i + 1;
31+
while (right < n + 2 && newHeights[i] <= newHeights[right]) {
32+
right++;
33+
}
34+
int area = (right - left - 1) * newHeights[i];
35+
res = Math.max(res, area);
36+
}
37+
return res;
38+
}
39+
}
40+
41+
42+
/*
43+
单调栈
44+
1、单调栈分为单调递增栈和单调递减栈
45+
1)单调递增栈即栈内元素保持单调递增的栈
46+
2)同理单调递减栈即栈内元素保持单调递减的栈
47+
2、操作规则(下面都以单调递增栈为例)
48+
1)如果新元素比栈顶元素大,就入栈
49+
2)如果新元素比栈顶元素小,那就一直把栈顶元素弹出来,直到栈顶元素比新元素小,然后新元素入栈
50+
3、规则效果(举例:栈[1, 5, 6],新元素2)
51+
(1)栈内的元素是递增的
52+
(2)当元素出栈时,这个新元素是出栈元素向右找第一个比它小的元素(2是6右边第一个比它小的元素)
53+
(3)当元素出栈后,新栈顶元素是出栈元素向左找第一个比它小的元素(5是6左边第一个比它小的元素)
54+
*/
55+
56+
57+
/*
58+
单调递增栈:
59+
1、暴力解法每次都要重新求当前柱子的左右边界,时间复杂度O(n²),空间复杂度O(1)
60+
核心思路是要找到当前柱子的左右边界 左边第一个高度小于它的位置 和 右边第一个高度小于它的位置,因此可以利用单调递增栈的特性,时间复杂度O(1),空间复杂度O(n)
61+
2、数组扩容,首尾添加哨兵0元素,作为最低点,方便作为任意高度的左右边界
62+
3、利用栈存放索引,这样既可以通过索引差获取宽度,也可以通过索引从数组获取高度
63+
3、遍历数组
64+
1)栈为空 或 当前高度大于栈顶高度 则当前索引入栈
65+
2)栈不为空 且 当前高度小于栈顶高度,则弹出栈顶高度作为矩形高度,新栈顶索引是左边界,当前索引是右边界,计算面积并保存最大面积。
66+
循环弹出处理,直到新栈顶高度比当前高度小,最后当前索引入栈,保证了栈内元素单调递增
67+
4、单调递增栈使得每一个出栈的柱子高度,都能通过 新栈顶索引 和 当前索引 快速获取左右边界,每一个柱子高度都会入栈,从而快速计算了每个柱子高度为矩形的最大面积
68+
*/
69+
class Solution {
70+
public int largestRectangleArea(int[] heights) {
71+
int res = 0;
72+
int n = heights.length;
73+
int[] newHeights = new int[n + 2];
74+
for (int i = 0; i < n; i++) {
75+
newHeights[i + 1] = heights[i];
76+
}
77+
Deque<Integer> stack = new ArrayDeque<>();
78+
for (int right = 0; right < n + 2; right++) {
79+
while (!stack.isEmpty() && newHeights[right] < newHeights[stack.peek()]) {
80+
int cur = stack.pop();
81+
int left = stack.peek();
82+
int area = (right - left - 1) * newHeights[cur];
83+
res = Math.max(res, area);
84+
}
85+
stack.push(right);
86+
}
87+
return res;
88+
}
89+
}

0 commit comments

Comments
 (0)