目录
一、题目描述
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例 1:
输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:6
解释:最大矩形如上图所示。
示例 2:
输入:matrix = []
输出:0
示例 3:
输入:matrix = [["0"]]
输出:0
示例 4:
输入:matrix = [["1"]]
输出:1
示例 5:
输入:matrix = [["0","0"]]
输出:0
提示:
- rows == matrix.length
- cols == matrix[0].length
- 0 <= row, cols <= 200
- matrix[i][j] 为 '0' 或 '1'
二、解题思路
这道题之前我没做过84题,所以一开始不会………
看题解的是时候有人说84题类似,就先去做了84题。由于类型是一样的一起记录吧。
84题:柱状图的最大矩形。
上图左边的柱状图中的最大面积为右边所描绘的区域。
84思路:
我们先对柱形编号index{0,1,2,3,4,5}、对应高度heights{2,1,5,6,2,3}。以4号柱子为例,4号柱子的高度为2,它所能围成的最大矩形的左边界为2号柱子,右边界为5号柱子,最大面积2*4=8。对每一个柱形都可以这么操作得到最大面积。现在的问题是怎么可以在时间代价小的情况下得到左右边界?
观察发现:左边界是左边第一个高度比当前小的柱形,左边比当前大的都需要跳过(不是边界),很容易想到单调栈的结构,每一个柱形入栈时都把栈顶比当前大的柱形弹出,直到栈顶的高度比当前的低,此时的柱形即是左边界减1位置的柱形。对于右边界可以采取同样的的策略,入栈顺序换成从右到左即可。
细节:这里左右两边都需要一个哨兵,因为会存在这样的情况,当前柱形在其左边的所有柱形中是最小的,此时栈会被弹空,此时的左边界应记为-1,表示是左边所有柱形当中最小的;同理右边的边界是列的大小+1。
85思路:
对于矩阵的每一行中的元素1,计算出现在其左边连续1的数量left[i][j]。比如题目实例1中的第一行的元素的left数组值分别为{1,0,1,0,0},第二行的left数组值为{1,0,1,2,3}…
在求出所有元素的left数组值后,把每一列都看成是一个柱形图,柱形的高度就是left[i][j]的值;依次求完所有列的最大矩形,取最大的矩形面积返回即为结果。
也就是说矩阵中的每一列就是一道84题。
三、代码实现
#include <bits/stdc++.h>
using namespace std;
int maximalRectangle(vector<vector<char>>& matrix) {
int r = matrix.size();
if (r == 0) {
return 0;
}
int c = matrix[0].size();
//求矩阵中每一个元素左边连续1的个数
vector<vector<int>> left(r, vector<int>(c, 0));
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (matrix[i][j] == '1') {
left[i][j] = (j == 0 ? 1 : left[i][j - 1] + 1);
}
}
}
//此处跟84题一模一样处理
//对每一列转换成柱状图求最大矩形
int res = 0;
for (int j = 0; j < c; j++) {
vector<int> up(r), down(r);
vector<int> monoSta;
//求左边高度小于当前的下标
for (int i = 0; i < r; i++) {
while (!monoSta.empty() && left[i][j] <= left[monoSta.back()][j]) {
monoSta.pop_back();
}
//左边以-1为哨兵
up[i] = (monoSta.empty() ? -1 : monoSta.back());
monoSta.push_back(i);
}
monoSta.clear();
//求右边高度小于当前的下标
for (int i = r - 1; i >= 0; i--) {
while (!monoSta.empty() && left[i][j] <= left[monoSta.back()][j]) {
monoSta.pop_back();
}
//左边以r为哨兵
down[i] = (monoSta.empty() ? r : monoSta.back());
monoSta.push_back(i);
}
for (int i = 0; i < r; i++) {
//更新每一个矩形的面积
res = max(res, (down[i] - up[i] - 1)*left[i][j]);
}
}
return res;
}
int main() {
vector<vector<char> > matrix = { {'1','0','1','0','0'},
{'1','0','1','1','1'},
{'1','1','1','1','1'},
{'1','0','0','1','0'} };
cout << maximalRectangle(matrix) << " ";
return 0;
}