柱状图中最大的矩形
难度:困难
题目描述
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例1
输入:heights = [2,1,5,6,2,3]
输出:10
示例2
输入: heights = [2,4]
输出: 4
题解
对于下标i
,要找到最大的下标j
和最小的下标k
,满足
j
<
i
<
k
j<i<k
j<i<k且
h
e
i
g
h
t
s
[
j
]
<
h
e
i
g
h
t
s
[
i
]
heights[j]<heights[i]
heights[j]<heights[i]和
h
e
i
g
h
t
s
[
k
]
<
h
e
i
g
h
t
s
[
i
]
heights[k]<heights[i]
heights[k]<heights[i],则存在一个宽度为
k
−
j
−
1
k-j-1
k−j−1,高度为
h
e
i
g
h
t
s
[
i
]
heights[i]
heights[i]的矩形,计算该矩形的最大面积
最为直观的做法是遍历每一个柱子,对于每个下标i
,向两边遍历寻找对应的下标j
和k
,得到以
h
e
i
g
h
t
s
[
i
]
heights[i]
heights[i]为高的最大矩形宽度并计算矩形的面积,但是此算法的时间复杂度为
O
(
n
2
)
O(n^2)
O(n2),会超过时间限制
创建两个长度为n
的数组
l
e
f
t
left
left和
r
i
g
h
t
right
right,对于每个下标i
,
l
e
f
t
[
i
]
left[i]
left[i]和
r
i
g
h
t
[
i
]
right[i]
right[i]分别记录对应的下标j
和k
。初始时,
l
e
f
t
left
left的全部元素为-1
,
r
i
g
h
t
right
right的全部元素为n
从左到右遍历数组
h
e
i
g
h
t
s
heights
heights,当遍历到下标i
时,进行如下操作:
- 如果栈不为空且栈顶下标对应的元素大于等于
h
e
i
g
h
t
s
[
i
]
heights[i]
heights[i],则将栈顶下标对应的
r
i
g
h
t
right
right值设为
i
,重复该操作直到栈为空或者下标的元素小于 h e i g h t s [ i ] heights[i] heights[i] - 如果栈不为空,则栈顶下标对应的元素小于
h
e
i
g
h
t
s
[
i
]
heights[i]
heights[i],因此将
i
对应的 l e f t left left值设为栈顶下标 - 将
i
入栈
遍历结束之后,对于每个下标i
,令
i
=
l
e
f
t
[
i
]
,
k
=
r
i
g
h
t
[
i
]
i=left[i],k=right[i]
i=left[i],k=right[i],则有
h
e
i
g
h
t
s
[
j
]
<
h
e
i
g
h
t
s
[
i
]
heights[j]<heights[i]
heights[j]<heights[i],
h
e
i
g
h
t
s
[
k
]
<
h
e
i
g
h
t
s
[
i
]
heights[k]<heights[i]
heights[k]<heights[i],如果
h
e
i
g
h
t
s
[
k
]
=
h
e
i
g
h
t
s
[
i
]
heights[k]=heights[i]
heights[k]=heights[i],那么高度为
h
e
i
g
h
t
s
[
i
]
heights[i]
heights[i]的最大矩形宽度为
k
−
j
−
1
k-j-1
k−j−1
所以最大面积为比对之后的最大值
想法代码
class Solution
{
public static void Main(String[] args)
{
Solution solution = new Solution();
int[] heights = { 2, 1, 5, 6, 2, 3 };
int ans = solution.LargestRectangleArea(heights);
Console.WriteLine(ans);
}
public int LargestRectangleArea(int[] heights)
{
int[] left = new int[heights.Length];
int[] right = new int[heights.Length];
Array.Fill(left, -1);
Array.Fill(right, heights.Length);
Stack<int> stack = new Stack<int>();
for (int i = 0; i < heights.Length; i++)
{
int height = heights[i];
while (stack.Count > 0 && heights[stack.Peek()] >= height)
{
right[stack.Pop()] = i;
}
if (stack.Count > 0)
{
left[i] = stack.Peek();
}
stack.Push(i);
}
int ans = 0;
for (int i = 0; i < heights.Length; i++)
{
ans = Math.Max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
}
s[i]);
}
return ans;
}
}