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