题目:给定一个 n × m 的网格,每个格子是 0 或 1。要找到一个只包含 1 的矩形区域,使得这个矩形包含的格子数最多。输出最大面积。
如果我们固定矩形的底部在第 i 行,那么问题就变成了:
每一列向上连续 1 的个数构成一个直方图
我们需要在这个直方图中找最大矩形面积
首先,从第一行开始逐步循环
1.找出每一次循环每一列的1的数量;
2.设置一个栈;
3.从第一列开始循环,找到j列比栈顶小的地方,即right(但不包含j列);
4.找到之后,开始计算面积;高度是栈顶的高度,然后踢出栈顶,宽度应该找一下左边的那一列是多少:
左边的那一列应该是现在的栈顶,如果现在的栈顶是空,则width是j前面的列;按要求循环;
5.所有循环完后,如果栈不为空,说明最后存在几列是递增的,在计算面积;
第一步:将二维问题转化为一维直方图问题
逐行扫描矩阵,维护一个 height 数组,height[j] 表示第 j 列从当前行向上连续 1 的个数。
- 如果当前格子是
1,则height[j]++ - 如果当前格子是
0,则height[j] = 0
这样每一行都得到一个直方图,问题转化为:在直方图中找最大矩形面积。
第二步:用单调栈求直方图的最大矩形
单调栈的核心思想:维护一个高度递增的栈,存储列下标。
具体步骤:
-
初始化一个空栈
-
遍历每一列
j(0 到 m-1) :- 当栈非空且
height[j] < height[栈顶]时,说明栈顶柱子的右边界已经确定(就是当前列j),需要弹出栈顶并计算面积: -
-
-
- 高度 =
height[栈顶]
- 高度 =
-
- 左边界 = 栈中下一个元素(如果栈空则为 -1)
- 宽度 =
j - 左边界 - 1 - 面积 = 高度 × 宽度
- 更新最大面积
-
- 将当前列
j入栈
- 当栈非空且
-
遍历结束后,处理栈中剩余元素:
- 这些柱子右边没有更矮的柱子,可以一直延伸到最后一列
- 右边界 =
m(最后一列 + 1) - 宽度 =
m - 左边界 - 1 - 同样计算面积并更新最大值
第三步:更新全局最大面积
每一行计算完后,用该行的最大面积更新全局最大值,最后输出结果。