首先说一下暴力方法,就是对于每一个元素,如果是1,那么就判断他的左上角是不是1,如果是,就扩展这个正方形,查看对应的一列和一行是不是全都是1,如果是就继续扩展
暴力法
虽然说我用的是动态规划,但是本质上还是暴力搜索
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
//dp[i][j]表示以(i,j)为右下角的正方形的最大面积
//挂羊头卖狗肉,其实本质还是暴力搜索
int ans = 0;
for(int i = 0;i < matrix.size();i++){
for(int j = 0;j < matrix[0].size();j++){
if(matrix[i][j] == '1'){
ans = 1;
break;
}
}
}
vector<vector<int>> dp(matrix.size());
for(int i = 0;i < matrix[0].size();i++)dp[0].push_back(matrix[0][i] - '0');
for(int i = 1;i < matrix.size();i++)dp[i].push_back(matrix[i][0] - '0');
for(int i = 1;i < matrix.size();i++){
for(int j = 1;j < matrix[i].size();j++){
if(matrix[i][j] == '0'){
dp[i].push_back(0);
}
else{
//这里的k表示左上角的最大正方形面积的边长
int k = sqrt(dp[i - 1][j - 1]);
bool flag = true;
//使得每次k减小1,为的就是防止正方形重叠的情况
while(k > 0){
flag = true;
for(int m = 1;m <= k;m++){
if(dp[i][j - m] == 0)flag = false;
}
for(int m = 1;m <= k;m++){
if(dp[i - m][j] == 0)flag = false;
}
if(flag == true)break;
k--;
}
if(flag)dp[i].push_back((k + 1) * (k + 1));
else dp[i].push_back(1);
}
ans = max(ans,dp[i][j]);
}
}
return ans;
}
};
这种做法有一个坑,就是这个例子
[["0","0","0","1"],["1","1","0","1"],["1","1","1","1"],["0","1","1","1"],["0","1","1","1"]]
存在正方形重叠的问题,所以才有了对k的迭代,每次使得k减1,从而获取最小边长
动态规划
这才是正确解法,暴力搜索的方式效率太低了
首先定义dp[i][j]表示以(i,j)结尾的最大正方形边长,有如下递推公式
dp[i][j] = min(dp[i - 1][j],dp[i][j - 1],dp[i - 1][j - 1]) + 1
可以理解为从当前位置的左面
,上面
,左上
选择最小的那个正方形,然后+1
为什么是最小呢?
我们可以看到,为了能够构成正方形,我们选择最小的那个正方形,那么另外两个比较大的矩形是一定可以覆盖到这个的,所以可以保证一定能构成正方形
推导过程可以看这里1277. 统计全为 1 的正方形子矩阵
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
int ans = 0;
vector<vector<int>>dp(matrix.size());
for(int i = 0;i < matrix.size();i++)dp[i].push_back(matrix[i][0] - '0');
for(int i = 1;i < matrix[0].size();i++)dp[0].push_back(matrix[0][i] - '0');
for(int i = 1;i < matrix.size();i++){
for(int j = 1;j < matrix[0].size();j++){
if(matrix[i][j] == '0')dp[i].push_back(0);
else dp[i].push_back(min(min(dp[i - 1][j],dp[i][j - 1]),dp[i - 1][j - 1]) + 1);
}
}
for(int i = 0;i < dp.size();i++){
for(int j = 0;j < dp[0].size();j++){
ans = max(ans,dp[i][j]);
}
}
return ans * ans;
}
};