Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.
Example:
Input:
[
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]
]
Output: 6
这个问题关键在于思路,如果人为判断是怎么做的呢,将我们的想法分解步骤化一下,一行一行考虑,一个位置一个位置考虑。
先考虑第一行:
对于0的位置我们不用考虑,到第一个1和第二个1它们都是宽度为1高度为1的矩形,相应的面积为1
第二行:
同样第三行和第四行:
依照这个思路我们可以细化得到一种详细的算法,通过维护三个长度与矩阵行长度等长的数组,h,l,r分别记录当前位置的矩形的高度,左侧边界索引,右侧边界索引+1(方便我们r-l就是矩阵的长);
我们直接扫描每一行,对每一行的第j个位置
比如题目中的例子,中各个位置的(l,r,h)可以写为:
(0,1,1),(0,5,0),(2,3,1),(0,5,0),(0,5,0)
(0,1,2),(0,5,0),(2,3,2),(2,5,1),(2,5,1)
(0,1,3),(0,5,1),(2,3,3),(2,5,2),(2,5,2)
(0,1,4),(0,5,0),(0,5,0),(3,4,3),(0,5,0)
//动态规划的方法,动态规划的不是面积,而是当前位置某种情况的面积
class Solution {
public:
int maximalRectangle(vector>& matrix) {
if(matrix.empty())return 0;
int m = matrix.size();
int n = matrix[0].size();
int res = 0;
vector h(n,0);
vector l(n,0);
vector r(n,n);
for(int i = 0; i < m; i ++){
//now_l和now_r分别记录当前行到当前位置的连续1序列的开始和结束
int now_l = 0, now_r = n;
for(int j = n - 1; j >= 0; j --){
if(matrix[i][j] == '1'){
r[j] = min(r[j],now_r);
}
else{
r[j] = n;
now_r = j;
}
}
for(int j = 0; j < n; j ++)
{
if(matrix[i][j] == '1'){
//h[j]记录的是第i行第j列的有效最高高度
h[j] ++;
//now_l是当前列能够延伸到的最左侧的索引,而l[j]是上一行包含j列有效连续1区段的能够延伸到最左侧的索引
//因为这个位置是1,所以该列的有效高度要加上这个1,而有效宽度的左侧要既满足这一行要求又要满足上一行要求
l[j] = max(l[j],now_l);
res = max(res, (r[j] - l[j])*h[j]);
// cout << i << "," << j << ": " << r[j] << "," << l[j] << "," << h[j] << "," << res << endl;
}
else{
h[j] = 0;
//如果当前矩阵中的字符为0,那么l和r的值为多少意义不大,因为h为0,对应的面积一定为0,将其分别定义为0和行长度
l[j] = 0;
now_l = j + 1;
}
}
}
return res;
}
};