给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例:
输入:
[
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]
]
输出: 6
方法1:暴力求解
class Solution {
public:
int help(int i, int j, vector<vector<char>>& matrix){
int re = 0, w = matrix[0].size();
for (int p = i; p<matrix.size(); ++p){
for (int q = j; q<w; ++q){
if (matrix[p][q] == '0' && q<matrix[0].size()){
w = q;
re = max(re, (q - j)*(p - i + 1));
}
if (matrix[p][q] == '1' && q == w - 1){
re = max(re, (w - j)*(p - i + 1));
}
}
}
return re;
}
int maximalRectangle(vector<vector<char>>& matrix) {
int re = 0;
for (int i = 0; i<matrix.size(); ++i){
for (int j = 0; j<matrix[0].size(); ++j){
if (matrix[i][j] == '1')
re = max(re, help(i, j, matrix));
}
}
return re;
}
};
方法2:借用84. 柱状图中最大的矩形的思路,二维矩阵每一层向上都可以看做一个直方图,输入矩阵有多少行,就可以形成多少个直方图。设置一个高度数组,如果当前行值为1的话,高度在原来基础上加1,否则置为0。求高度过程中采用了动态规划的思想。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int re = 0;
vector<int> s;
heights.push_back(0);//加上这个,可以少写最后一段,很简洁
for (int i = 0; i<heights.size(); ++i){
while (!s.empty() && heights[s.back()]>heights[i]){
int h = heights[s.back()];
s.pop_back();
int temp = s.size() ? h * i : h * (i - s.back());
re = max(re, temp);
}
s.push_back(i);
}
return re;
}
int maximalRectangle(vector<vector<char>>& matrix) {
if(matrix.empty() || matrix[0].empty()) return 0;
int re = 0;
vector<int> heights(matrix[0].size(), 0);
for (int i = 0; i<matrix.size(); ++i){
for (int j = 0; j<matrix[0].size(); ++j){
matrix[i][j] == '1' ? heights[j]++ : heights[j]=0;
}
re=max(re, largestRectangleArea(heights));
}
return re;
}
};
方法3:方法1暴力求解,之前的行和列的结果都没利用上。方法2中,用上了之前每一列的结果,行的结果没用上。方法3是最好的,之前的行和列的结果都利用上了。新建两个数组left和right分别表示构成的矩形的左边界和右边界的位置,新建两个变量cur_left, cur_right分别表示当前行左边界和右边界的位置。左边界存与该元素相连的最左端的1的位置,右边界存与该元素相连的最右端的1的位置的下一个位置(方便计算)。如果当前元素是‘0’的话,那么左边界就是0,右边界就是n。O(n*m)的时间复杂度。
1、当matrix[i][j] == '1'时:
(1)cur_left, cur_right就为之前的值。
(2)heights[j]++
(3)left(i,j) = max(left(i-1,j), cur_left),right(i,j) = min(right(i-1,j), cur_right)
2、当matrix[i][j] == '0'时:
(1)cur_left变成j+1,cur_right就为j
(2)heights[j]=0
(3)left(i,j) =0,right(i,j) =n.
3、cur_left从左往右遍历,cur_right从右往左遍历
class Solution {
public:
int maximalRectangle(vector<vector<char>>& matrix) {
if(matrix.empty() || matrix[0].empty()) return 0;
int re = 0, n=matrix[0].size();
vector<int> pri(n, 0), left(n, 0), right(n, n);
for (int i = 0; i<matrix.size(); ++i){
int cur_left=0, cur_right=n;
for (int j = 0; j<n; ++j){
if(matrix[i][j] == '1'){
pri[j]++;
left[j]=max(left[j], cur_left);
}
else{
left[j]=0;
cur_left=j+1;
pri[j]=0;
}
}
for(int j=n-1; j>=0; --j){
if(matrix[i][j] == '1'){
right[j]=min(right[j], cur_right);
}
else {
right[j]=n;
cur_right=j;
}
re=max(re, pri[j]*(right[j]-left[j]));
}
}
return re;
}
};