Problem:
Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and return its area.
For example, given the following matrix:
1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0Return 4.
Analsysis:
本题解法需要利用动态规划。首先我们能注意到一个变长大于1的正方形必须在左上角包含一个较小的正方形。所以,一个面积达到最大的正方形一定可以从一个位于其左上角低一阶的“最大”正方形通过加两条边和一个右下的顶点得到。其次,这个低一阶的最大正方形不是完全可以用来构造新的正方形。根据正方形的规则,在低一阶最大正方形的外侧加的两条边都必须全部由1组成。所以,我们要从新一个右下顶点出发,找到新加入的两条“边”的长度:如果长于左上的“最大”正方形,则把这个低一阶正方形全部用来构造新正方形;否则,用较短的新加入的边(加1)做边长,构造正方形。这样,我们就可以建立递归方程:设dp[i][j]是右下角顶点位置为(i, j)的正方形的面积,则dp[i][j] = min(min(最长的由1组成的结束于(i, j)的行,最长的由1组成的结束于(i, j)的列), d[i - 1][j - 1]) + 右侧边 + 底下的边 + 1。
Solutions:
C++:
The soution I gave: (20 ms)
int maximalSquare(vector<vector<char>>& matrix)
{
int max_sq = 0;
if(matrix.empty() || matrix[0].empty())
return max_sq;
int size_row = matrix.size();
int size_col = matrix[0].size();
int dp[size_row][size_col];
for(int i = 0; i < size_row; ++i) {
for(int j = 0; j < size_col; ++j) {
dp[i][j] = 0;
}
}
for(int i = 0; i < size_row; ++i) {
if(matrix[i][0] == '1') {
dp[i][0] = 1;
max_sq = 1;
}
}
for(int i = 0; i < size_col; ++i) {
if(matrix[0][i] == '1') {
dp[0][i] = 1;
max_sq = 1;
}
}
for(int row = 1; row < size_row; ++row) {
for(int col = 1; col < size_col; ++col) {
if(matrix[row][col] == '0') {
dp[row][col] == 0;
continue;
}
if(!dp[row - 1][col - 1]) {
dp[row][col] = 1;
continue;
}
int row_1 = 0;
for(int i = col - 1; i >=0; --i) {
if(matrix[row][i] == '0')
break;
++row_1;
}
int col_1 = 0;
for(int i = row - 1; i >=0; --i) {
if(matrix[i][col] == '0')
break;
++col_1;
}
int new_size = min(min(row_1, col_1), static_cast<int>(sqrt(dp[row - 1][col - 1]))) + 1;
dp[row][col] = new_size * new_size;
if(dp[row][col] > max_sq)
max_sq = dp[row][col];
}
}
return max_sq;
}
A solution I found on the internet (http://blog.csdn.net/yezizp/article/details/46347967 ): (12 ms)
int maximalSquare(vector<vector<char>>& matrix)
{
int result = 0;
if(matrix.empty())
return result;
const int n = matrix.size();
const int m = matrix[0].size();
vector<vector<int> > dp(n + 1, vector<int>(m + 1, 0));
for(int i = 0; i < n; ++i)
for(int j = 0; j < m; ++j){
if(matrix[i][j] == '1'){
dp[i + 1][j + 1] = min(dp[i][j], min(dp[i + 1][j], dp[i][j + 1])) + 1;
result = max(result, dp[i + 1][j + 1]);
}
}
return result * result;
}