Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.
给定一个充满0和1的矩阵,要求出范围全为1的矩阵的面积。
算法一,动态规划
此题,以每行为底,都可以转换成是一个Largest Rectangle in Histogram问题。
每个点,先算出所在矩形的高度,左边界,右边界。然后就能求出这个点所在矩形的面积了。
而高度,左边界,右边界,都可以按照DP思路算出。
已知上一行的高度,如果当前元素为1,则高度+1,否则清0.
left(i,j) = max(left(i-1,j), curleft) 逐步向右收缩其左边矩
right(i,j) = min(right(i-1,j), curright) 逐步向左收缩其右边矩
对curleft设置,如果当前元素为1,则不修改curleft。否则将其置0。置0,意味着下一行,该列时,其左边界,可能延伸至最起始处。即它之前,全为1.
同理,对curright,当前元素为0时,将其置为一个大值。本行度高度为0了。但下一行的,该列时,其右边界,可能延伸到最远处。即在他之后,全为1.
此代码在leetcode上实际执行时间为18ms。
class Solution {
public:
int maximalRectangle(vector<vector<char> > &matrix) {
if (matrix.empty() || matrix[0].empty())
return 0;
int area = 0;
const int m = matrix.size();
const int n = matrix[0].size();
vector<int> height(n);
vector<int> left(n);
vector<int> right(n, n);
for (int i=0; i<m; i++) {
int curLeft = 0;
for (int j=0; j<n; j++) {
height[j] = matrix[i][j] == '1' ? height[j]+1 : 0;
left[j] = matrix[i][j] == '1' ? max(left[j], curLeft) : 0;
curLeft = matrix[i][j] == '1' ? curLeft : j+1;
}
int curRight = n-1;
for (int j=n-1; j>=0; j--) {
right[j] = matrix[i][j] == '1' ? min(right[j], curRight) : n;
curRight = matrix[i][j] == '1' ? curRight : j-1;
}
for (int j=0; j<n; j++)
area = max(area, (right[j]-left[j]+1)*height[j]);
}
return area;
}
};
以上算法参考自:
https://leetcode.com/discuss/20240/share-my-dp-solution
算法二。借鉴题目Largest Rectangle in Histogram的解法。
此题,以每行为底,都可以转换成是一个Largest Rectangle in Histogram问题。
不同的是,高度表height,需要自己算。
求出height后,其他同Largest Rectangle in Histogram思路一样。
class Solution {
public:
int maximalRectangle(vector<vector<char> > &matrix) {
if (matrix.empty() || matrix[0].empty())
return 0;
int area = 0;
const int m = matrix.size();
const int n = matrix[0].size();
vector<int> height(n+1);
for (int i=0; i<m; i++) {
stack<int> s;
bool flag = true;
for (int j=0; j<=n;) {
if (flag && j!=n) {
height[j] = matrix[i][j]=='1' ? height[j]+1 : 0;
flag = false;
}
if (s.empty() || height[j] >= height[s.top()]) {
s.push(j++);
flag = true;
}
else {
const int altitude = height[s.top()];
s.pop();
const int left = s.empty() ? 0 : s.top()+1;
area = max(area, (j-left) * altitude);
}
}
}
return area;
}
};