LeetCode LCR 039. 柱状图中最大的矩形
题目描述


题意分析
每根柱子宽度为 $1$,矩形必须覆盖一段连续柱子。对选定区间,矩形高度最多为区间最小柱高,因此面积是“最小高度乘连续宽度”。可以反过来固定矩形高度,寻找它能覆盖的最宽区间。
柱高允许为零,等高柱子可以组成更宽的矩形。零高度会阻断正面积矩形;全零时答案为 $0$。
解法:单调不减栈
核心思路
[!blue]
从左到右扫描,用栈保存尚未结算的柱子下标,栈底到栈顶的高度单调不减。当前高度不低于栈顶时,已有柱子的矩形仍可能向右扩展,暂不结算,直接把当前下标入栈。
当前高度更矮时,栈顶高度
height已无法扩展到当前位置i,可以弹出并计算面积。弹出后的栈顶记为left,空栈时取-1;从left + 1到i - 1的柱子都不低于height,所以本次矩形宽度为i - left - 1。继续弹栈,直到剩余栈顶不高于当前柱子,再压入当前下标。代码只在高度严格大于当前值时弹栈,所以
left的高度可能与弹出柱子相等,本次面积未必是这个高度的最大面积。同一可延伸区间中的等高柱子会从右向左依次结算,最靠左的那根最终越过全部等高位置,覆盖到真正更矮的左边界,因此最大宽度不会遗漏。任意最优矩形都有一个最低柱高,把它扩展到左右更矮柱子之前只会增大面积;这段最低高度最终会由栈中的某个等高候选完整结算。扫描末尾再处理一个虚拟高度 $0$,即可弹出所有剩余正高度候选;零高度残留不会贡献面积。
解题步骤
- 创建下标栈,最大面积初始化为 $0$。
- 扫描位置 $0$ 到 $n$;位置 $n$ 的当前高度直接取 $0$,不读取
heights[n]。- 栈顶高度严格大于当前高度时弹出,用新栈顶或
-1作为left,计算height * (i - left - 1)。- 完成所有弹栈后压入当前下标。处理完虚拟位置后结束扫描,返回最大面积。
代码实现
class Solution {
public int largestRectangleArea(int[] heights) {
int[] stack = new int[heights.length + 1];
int top = -1;
int ans = 0;
for (int i = 0; i <= heights.length; i++) {
int cur = i == heights.length ? 0 : heights[i];
while (top >= 0 && heights[stack[top]] > cur) {
// 弹出的柱子以自身高度为矩形最矮高度,左右边界此时已确定。
int height = heights[stack[top--]];
int left = top >= 0 ? stack[top] : -1;
ans = Math.max(ans, height * (i - left - 1));
}
stack[++top] = i;
}
return ans;
}
}
func largestRectangleArea(heights []int) int {
stack := make([]int, 0)
ans := 0
for i := 0; i <= len(heights); i++ {
cur := 0
if i < len(heights) {
cur = heights[i]
}
for len(stack) > 0 && heights[stack[len(stack)-1]] > cur {
// 当前下标是右边界,弹出后的栈顶给出本次左边界。
height := heights[stack[len(stack)-1]]
stack = stack[:len(stack)-1]
left := -1
if len(stack) > 0 {
left = stack[len(stack)-1]
}
area := height * (i - left - 1)
if area > ans {
ans = area
}
}
stack = append(stack, i)
}
return ans
}
复杂度分析
- 时间复杂度:$O(n)$。每个真实下标入栈一次、至多出栈一次,末尾只多处理一个虚拟位置。
- 空间复杂度:$O(n)$。栈最多保存 $n+1$ 个下标,其中包含末尾的虚拟位置。
关键点总结
[!green]
- 更矮柱子确定右边界,弹栈后才能得到本次计算所用的左边界。
- 严格
>弹栈允许等高柱子共存,最大宽度由较靠左的同高度候选覆盖。- 末尾虚拟高度 $0$ 负责结算仍可向右延伸的正高度矩形。
易错点总结
[!yellow]
- 宽度为
i - left - 1,左右两个边界位置都不计入本次区间。- 不处理末尾虚拟高度,会漏掉直到数组结束都未遇到更矮柱子的候选。
- 弹栈后的左边界可能等高,不能把每次弹栈都解释为找到左右两个严格更矮的位置。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 85. 最大矩形 | 困难 | 以每一行为底,逐列累计向上连续1的个数作为柱高,遇0清零;再复用本题求柱状图最大矩形,取各行结果的最大值。 |
| 42. 接雨水 | 困难 | 同样利用高度与边界计算面积,原题求凹槽容水,本题求由最矮柱限制的完整矩形。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!