力扣解题思路:221. 最大正方形

221. 最大正方形

思路:在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。

输入:
matrix = [["1","0","1","0","0"],
          ["1","0","1","1","1"],
          ["1","1","1","1","1"],
          ["1","0","0","1","0"]]

输出:4

每当看到这种正方形或者矩形的题目,都会形成一种本能的反应,就是找到两个点,即左上和右下顶点,因为固定这两个点,整个正方形也就固定了。

首先采用暴力法,也就是对每一个点,遍历其可能出现的所有正方形的长度,返回满足条件的最长的就可以了:

public int maximalSquare(char[][] matrix) {
    int max = 0;
    for (int i = 0; i < matrix.length; i++)
        for (int j = 0; j < matrix[0].length; j++)
            if (matrix[i][j] == '1') max = Math.max(max, function(matrix, i, j));
    return max;
}
public int function(char[][] matrix, int i, int j) {
    int m = 0;
    for (; m + j < matrix[0].length && m + i < matrix.length; m++) {
        for (int p = j; p <= j + m; p++)
            if (matrix[m+i][p] != '1') return m * m;
        for (int q = i; q < i + m; q++)
            if (matrix[q][m+j] != '1') return m * m;
    }
    return m * m;
}

另一种方式就是动态规划,这需要我们发现一个规律来更新动态方程,我们定义dp[i][j]表示以第i行第j列为右下角所能构成的最大正方形边长,那么如何更新呢?

当我们判断以某个点为正方形右下角时最大的正方形时,那它的上方,左方和左上方三个点也一定是某个正方形的右下角,否则该点为右下角的正方形最大就是它自己了。这是定性的判断,那具体的最大正方形边长呢?我们知道,该点为右下角的正方形的最大边长,最多比它的上方,左方和左上方为右下角的正方形的边长多1,最好的情况是是它的上方,左方和左上方为右下角的正方形的大小都一样的,这样加上该点就可以构成一个更大的正方形。 但如果它的上方,左方和左上方为右下角的正方形的大小不一样,合起来就会缺了某个角落,这时候只能取那三个正方形中最小的正方形的边长加1了。假设dpi表示以i,j为右下角的正方形的最大边长,则有 :

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

举个例子,如果dp[i-1][j-1], dp[i-1][j], dp[i][j-1]位置其中有一个位置为0,都是证明无法构成正方形的,因此dp[i][j] = 0+1 = 1,也就是只有自身的一个正方形,同样的道理,再举个例,如果dp[i-1][j-1], dp[i-1][j], dp[i][j-1]分别为123,那么无论如何都是可以构成2乘2的正方形的,画个图就可以清晰明了啦~~
代码很简单,也不需要初始化数组,因为其他位置默认为0就可以啦:

public int maximalSquare(char[][] matrix) {
    /**
    dp[i][j]表示以第i行第j列为右下角所能构成的最大正方形边长, 则递推式为: 
    dp[i][j] = 1 + min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]);
    **/
    int m = matrix.length;
    if(m < 1) return 0;
    int n = matrix[0].length;
    int max = 0;
    int[][] dp = new int[m+1][n+1];
    for(int i = 1; i <= m; ++i) {
        for(int j = 1; j <= n; ++j) {
            if(matrix[i-1][j-1] == '1') {
                dp[i][j] = 1 + Math.min(dp[i-1][j-1], Math.min(dp[i-1][j], dp[i][j-1]));
                max = Math.max(max, dp[i][j]); 
            }
        }
    }
    return max*max;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值