最大正方形

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

示例:

输入:

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

输出: 4

思路一:暴力美学
直接从左上角遍历所有元素,遇到1,就开始判断它的最大正方形:

  1. 设置一个len,初始值为1,代表这个正方形的边长;
  2. 设置标志位flag,一旦在检测过程中发现了0,就置为false;
  3. 然后向右和向下遍历此元素的一整行/列(长为len)是否全为1。是则len++,然后继续遍历;否则置标志位为false。
  4. 最后返回最大的len所对应的面积

时间复杂度:O((mn)2),最坏情况下,我们需要遍历整个矩阵寻找每个 1。
空间复杂度:O(1),没有使用额外的空间。

思路二:动态规划
看到这个题的标签是动态规划时,我就很疑惑,这个题怎么能用动态规划呢,看了看题解才发现,奥~原来是这个意思。

若某格子值为 1 ,则以此为右下角的正方形的最大边长为:上面的正方形左面的正方形左上的正方形中,最小的那个,再加上此格。

用图的方法表示:

可以看到,

  • 图1:受限于左上的0
  • 图2:受限于上边的0
  • 图3:受限于左边的0

时间复杂度:O(mn)
空间复杂度:O(mn)

所以,代码如下:

class Solution {
    public int maximalSquare(char[][] matrix) {
        if(matrix==null || matrix.length==0)    return 0;
        int nr = matrix.length;
        int nc = matrix[0].length;
        int max = 0;
        //这样的目的是为了避免手动设置边界值
        int[][] dp = new int[nr+1][nc+1];
        for(int r=1;r<nr+1;r++){
            for(int c=1;c<nc+1;c++){
                if(matrix[r-1][c-1]=='1'){
                    dp[r][c] = Math.min(Math.min(dp[r-1][c],dp[r-1][c-1]),dp[r][c-1])+1;
                    max = Math.max(dp[r][c],max);
                }
            }
        }
        return max*max;
    }
}

思路三:优化动态规划
这个理解起来,对于我这种白痴而言就更难了。其实我们的遍历是一行一行的遍历的。那么只用一个一维数组dp[]保存一行的边长是否可行呢?
是可行的。每一次换新的一行,都是dp的一次更新换代。那么原来的dp代表的就是上一行。
所以,假如我们用prev来存储上一行的dp[c],来代表下一列左上角的值;然后用dp[c-1]来代表左边的值;用dp[c]来代表上面的值。就可以只用一维数组就可以表示了!!
这样一来,空间复杂度仅为O(n)。

class Solution {
    public int maximalSquare(char[][] matrix) {
        if(matrix==null || matrix.length==0)    return 0;
        int nr = matrix.length;
        int nc = matrix[0].length;
        int max = 0;
        int prev = 0;
        //这样的目的是为了避免手动设置边界值
        int[] dp = new int[nc+1];
        for(int r=1;r<nr+1;r++){
            for(int c=1;c<nc+1;c++){
                int temp = dp[c];   //存储下来,留给下一列用
                if(matrix[r-1][c-1]=='1'){
                    dp[c] = Math.min(Math.min(dp[c-1],prev),dp[c])+1;
                    max = Math.max(dp[c],max);
                }else{
                    dp[c] = 0;
                }
                prev = temp;
            }
        }
        return max*max;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值