时月oe

博客园 首页 新随笔 联系 订阅 管理

最大正方形

首先说一下暴力方法,就是对于每一个元素,如果是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;
    }
};

posted on 2022-03-19 20:08  时月oe  阅读(38)  评论(0编辑  收藏  举报