题目
给定一个非负整数数组 heights,表示一个柱状图中各个柱子的高度。每个柱子的宽度为1。找到柱状图中面积最大的矩形。
示例
输入: [2,1,5,6,2,3]
输出: 10
解释: 上图所示的矩形即为面积最大的矩形,其面积为2x5 = 10。
思路:单调栈
- 首先,我们遍历每个柱子,并维护一个递增的栈。
- 对于每个柱子,如果当前高度大于栈顶元素的高度,我们将其入栈。
- 否则,我们从栈中不断弹出元素,直到栈顶元素小于当前柱子的高度。
- 在这个过程中,我们计算以弹出元素为高度的矩形的面积,并更新最大面积。
代码实现
function largestRectangleArea(heights: number[]): number {
const stack: number[] = []; // 创建一个空栈,用于存储数组索引
let maxArea = 0; // 初始化最大面积为0
for (let i = 0; i <= heights.length; i++) { // 遍历数组,包括最后一个虚拟索引
while (stack.length > 0 && (i === heights.length || heights[i] < heights[stack[stack.length - 1]])) {
// 当栈不为空且当前高度小于栈顶元素对应的高度时执行循环
const heightIndex = stack.pop()!; // 弹出栈顶元素的索引
const height = heights[heightIndex]; // 获取栈顶元素对应的高度
// 计算矩形的宽度
const width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1;
// 更新最大面积
maxArea = Math.max(maxArea, height * width);
}
stack.push(i); // 将当前索引入栈
}
return maxArea; // 返回最大面积
}
解释下:
-
首先,创建一个空栈
stack
和初始最大面积maxArea
为0。 -
开始遍历数组:
-
当
i = 0
时,将索引0入栈。此时栈中的元素为[0]。 -
当
i = 1
时,由于当前元素1小于栈顶元素2,进入while循环,弹出栈顶元素2并计算矩形面积。- 弹出栈顶元素2,得到栈中的元素为[0]。
- 计算矩形宽度:
width = i - stack[stack.length - 1] - 1 = 1 - 0 - 1 = 0
。 - 更新最大面积:
maxArea = Math.max(maxArea, height * width) = Math.max(0, 2 * 0) = 0
。
-
将索引1入栈。此时栈中的元素为[0, 1]。
-
当
i = 2
时,由于当前元素5大于栈顶元素1,直接将索引2入栈。此时栈中的元素为[0, 1, 2]。 -
当
i = 3
时,由于当前元素6大于栈顶元素5,直接将索引3入栈。此时栈中的元素为[0, 1, 2, 3]。 -
当
i = 4
时,由于当前元素2小于栈顶元素6,进入while循环,弹出栈顶元素3并计算矩形面积。- 弹出栈顶元素3,得到栈中的元素为[0, 1, 2]。
- 计算矩形宽度:
width = i - stack[stack.length - 1] - 1 = 4 - 2 - 1 = 1
。 - 更新最大面积:
maxArea = Math.max(maxArea, height * width) = Math.max(0, 6 * 1) = 6
。
-
继续进入while循环,弹出栈顶元素2并计算矩形面积。
- 弹出栈顶元素2,得到栈中的元素为[0, 1]。
- 计算矩形宽度:
width = i - stack[stack.length - 1] - 1 = 4 - 1 - 1 = 2
。 - 更新最大面积:
maxArea = Math.max(maxArea, height * width) = Math.max(6, 5 * 2) = 10
。
-
将索引4入栈。此时栈中的元素为[0, 1, 4]。
-
当
i = 5
时,由于已经遍历完数组,进入while循环,弹出栈顶元素4并计算矩形面积。- 弹出栈顶元素4,得到栈中的元素为[0, 1]。
- 计算矩形宽度:
width = i - stack[stack.length - 1] - 1 = 5 - 1 - 1 = 3
。 - 更新最大面积:
maxArea = Math.max(maxArea, height * width) = Math.max(10, 2 * 3) = 10
。
-
-
最终得到最大矩形面积为10,即函数返回值为10。
复杂度分析
- 时间复杂度:O(N),其中 N 表示柱状图的长度。我们只需要遍历一次柱状图中的每个元素,并且每个元素最多入栈一次和出栈一次。
- 空间复杂度:O(N),使用了一个栈来存储柱子的索引,栈中的元素数量不会超过柱状图的长度。