最大正方形

*************

C++

leetcode:. - 力扣(LeetCode)

*************

首先看一眼题目:

这个形状一看,起手就是构造一个二维矩阵dp,初始化所有的元素为 0 。为什么呢,因为目前我只会矩阵。跟之前一样,我还是喜欢举个简单的例子,还是4 ✖️ 4的矩阵,方便理解,算了,还是举个5 ✖️ 5的,方便我理解。

matrixarray
1010000000
1011100000
1111100000
1001000000
1000000000

简单的理解就是,初始化一个 矩阵dp,然后熟练的将第一行 && 第一列填充,为什么使用 && 这个呢,是因为这个代表同时满足的意思, || 这个代表只要满足一个就行的意思。这个代码比较的简单。回头看这段代码的时候,是一眼就能发现一个问题的,应该是 int j; 

matrixarray
1010010100
101111
111111
100101
100001

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
       int m = matrix.size; // get the rows
       int n = matrix[0].size(); // get the columns
       vector<vector<int>> dp(m, vector<int>(n, 0)); // initialise the array

       // make dp the first row elements totally equal the first line of the matrix
       for (j = 0; j < n; j++){
        dp[0][j] = matrix[0][j];
       }

       
    }
};

再然后就是填充剩下的一列,困难来到了怎么判断,这个时候来那个矩阵来帮助思考一下。最开始的想法就是填充以下的元素。最简单的想法就是 穷举法, 没错我很爱穷举法,主要是因为在妇联3,奇异博士穷举了好多种可能,最后取了一种。扯远了,话说回来,主要是因为穷举法最能顺应直觉,但是这里我不太会。

我还是喜欢矩阵多一点,矩阵向量,太妙了。因为只有数字0 or 1,所以第一行0就代表没有,1就代表有一个边长为1的正方形,因此直接复制第一行到dp。从dp[1][0]开始,也就是说第二行第一列开始,我们这里开始分析,右下角那个是最好分析的,为什么,因为左上角是固定的,右下角可以直接填充。

matrixarray
1010010100
1011110111
111111
100101
100001

 

 

 

 

 

 

举例, dp[1][1]就是代表第二行第二列,如果是0的话,直接排除了当前单元格跟其他单元格组成正方形的可能性,因此对于是0的单元格,不能用1填充,在这里,不能让0和1相遇,会出问题的。dp[1][2]的值也是1,他不能与 左边 || 左上 || 正上方的格子组成一个正方形,所以只能是他自己组成一个正方形,所以边长是1。dp[1][3]同理,由于正上方是0,所以也不能组成边长是2的正方形。

matrixarray
1111111111
1111112222
1111112333
1111112344
1111112345

这里并不能总结出什么规律,但是稍微查一下就知道这里有一个很多简单的方法可以借鉴,就是 dp[i][j]的数值是由dp[i][j - 1] && dp[i - 1][j] && dp[i - 1][j - 1]共同决定的,即dp[i][j] = min(dp[i][j - 1] , dp[i - 1][j] , dp[i - 1][j - 1]) + 1。具体的原理是什么呢,举例: 如上图,很好理解,我解释不出来,但是很好记,就是在最小值上+1就行。因此填充下面的代码就变得简单起来。

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = array.size(); // get the rows
        int n = array[0].size(); // get the columns
        vector<vector<int>> dp(m, vector<int>(n, 0)); // initialise the array and make the elements equal 0

        // initialise the first row
        for (int j = 0; j < n; j++){
            dp[0][j] = matrix[0][j];
        }

        // initialise the first column
        for (int i = 0; i < m; i++){
            dp[i][0] = matrix[i][0];
        }

        // fill the rest of the elements
        for (int i = 1; i < m; i++){
            for (int j = 1; j < n; j++){
                if (matrix[i][j] == 0){
                    dp[i][j] = 0;
                } else {
                    dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1;
                }
            }
        }
    }
};

 这里的主要的代码就写好了,但是这题目的要求是算面积,这一步只找到了最大的正方形的边长。上过小学的都知道这里的门道有多深,正方形的面积等于边长的平方,因此可以补充剩下的return 代码。

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = array.size(); // get the rows
        int n = array[0].size(); // get the columns
        vector<vector<int>> dp(m, vector<int>(n, 0)); // initialise the array and make the elements equal 0

        // initialise the first row
        for (int j = 0; j < n; j++){
            dp[0][j] = matrix[0][j];
        }

        // initialise the first column
        for (int i = 0; i < m; i++){
            dp[i][0] = matrix[i][0];
        }

        // fill the rest of the elements
        for (int i = 1; i < m; i++){
            for (int j = 1; j < n; j++){
                if (matrix[i][j] == 0){
                    dp[i][j] = 0;
                } else {
                    dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1;
                }
            }

            int macSide = max(dp[i][j]);
        }

        int maximalSquare = maxSide * maxSide;
        return maximalSquare;
    }
};

这里运行一下,不出意外的报错了。

简单的分析一下,最开始给的是matrix而不是array,所以换掉。

其次是min的语法错了,这里改一下语法。

当然最重要的是,matrix是char类型,dp是 int 类型,需要转化。

最终改正完全的代码是这样的

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = matrix.size(); // get the rows
        int n = matrix[0].size(); // get the columns
        vector<vector<int>> dp(m, vector<int>(n, 0)); // initialise the array and make the elements equal 0

        // initialise the first row
        for (int j = 0; j < n; j++){
            dp[0][j] = int(matrix[0][j]) - '0'; // convert char into int
        }

        // initialise the first column
        for (int i = 0; i < m; i++){
            dp[i][0] = int(matrix[i][0]) - '0';  // convert char into int
        }

        // fill the rest of the elements
        int maxSide = 0; // creat a place to store the longest side 
        for (int i = 1; i < m; i++){
            for (int j = 1; j < n; j++){
                if (matrix[i][j] == '0'){
                    dp[i][j] = 0;
                } else {
                    dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
                }
                maxSide = max(maxSide, dp[i][j]);
            }
        }
        int maximalSquare = maxSide * maxSide;
        return maximalSquare;
    }
};

这段代码是能跑起来的,但是还是错误了,为什么的呢?

这里需要重新检查一下代码,最大的边长需要在一开始就得初始化,一个解决方法是这样的,随时更新maxSide.

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = matrix.size(); // get the rows
        int n = matrix[0].size(); // get the columns
        vector<vector<int>> dp(m, vector<int>(n, 0)); // initialise the array and make the elements equal 0
        int maxSide = 0; // creat a place to store the longest side 

        // initialise the first row
        for (int j = 0; j < n; j++){
            dp[0][j] = matrix[0][j] - '0'; // convert char into int
            maxSide = (maxSide, dp[0][j]);
        }

        // initialise the first column
        for (int i = 0; i < m; i++){
            dp[i][0] = matrix[i][0] - '0';  // convert char into int
            maxSide = max(maxSide, dp[i][0]);
        }

        // fill the rest of the elements
        
        for (int i = 1; i < m; i++){
            for (int j = 1; j < n; j++){
                if (matrix[i][j] == '0'){
                    dp[i][j] = 0;
                } else {
                    dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
                }
                maxSide = max(maxSide, dp[i][j]);
            }
        }
        int maximalSquare = maxSide * maxSide;
        return maximalSquare;
    }
};

如果我不想随时更新maxSide怎么办呢?那就看一下代码到底哪里出错了。以Case 2 为例:

matrixdp
0100
1000

第一步肯定是将dp初始化为0;

matrixdp
0101
1010

第二步是将第一行 && 第一列填充   

                                                             

matrixdp
0100
1000

 

第三步是将第二行 && 第二列填充 ,这里的代码是

如果该单元格为0,那么dp填充0;否则才计数。

感觉是这里出了问题,换一下先后顺序。改成:

如果单元格是1,进行计数;如果单元格不是1,就填0;

这里的是没问题的,最后试了很多次,还是得更新第一行和第二行的maxSide的值。如果不更新的话,那么在第一行和第一列的时候就是维持初始值0。在填充第二行第二列的时候,maxSide的值依然维持是0。第27行开始,第二行第二列,应该是1 的,但是仅仅是因为没有更新,这里的原理我还不是很清楚。

dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;

// dp[1][1] = min(0, 1, 1) + 1

没有关系,过几天再次看这个题目的时候,应该能理解。

最后,最终提交的代码是这个样子的:

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = matrix.size(); // get the rows
        int n = matrix[0].size(); // get the columns
        int maxSide = 0; // creat a place to store the longest side 
        vector<vector<int>> dp(m, vector<int>(n, 0)); // initialise the array and make the elements equal 0

        // initialise the first row
        for (int j = 0; j < n; j++){
            dp[0][j] = matrix[0][j] - '0'; // convert char into int
            if (dp[0][j] == 1) {
                maxSide = 1; // update maxSide if there's a '1' in the first row
            }
        }

        // initialise the first column
        for (int i = 0; i < m; i++){
            dp[i][0] = matrix[i][0] - '0';  // convert char into int
            if (dp[i][0] == 1) {
                maxSide = 1; // update maxSide if there's a '1' in the first column
            }
        }

        // fill the rest of the elements
        
        for (int i = 1; i < m; i++){
            for (int j = 1; j < n; j++){
                if (matrix[i][j] == '1'){
                    dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
                    maxSide = max(maxSide, dp[i][j]);
                } 
                // else {
                //     dp[i][j] = 0;
                // }
            }
        }

        
        int maximalSquare = maxSide * maxSide;
        return maximalSquare;
    }
};

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值