Leetcode 221. 最大正方形

  • Leetcode 221. 最大正方形
  • 题目
    • 在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。
    • m == matrix.length
    • n == matrix[i].length
    • 1 <= m, n <= 300
    • matrix[i][j] 为 ‘0’ 或 ‘1’
  • 解法
    • 动态规划+状态压缩:定义三个 dp,分别为:
      • rowDp[i][j]:在第 i 行当前节点(含)往前连续有多少个 1
      • colDp[i][j]:在第 j 列当前节点(含)往上连续有多少个 1
      • squareDp[i][j]:以当前节点为右下角,连续 1 的最大正方形边长
    • 此时循环矩阵,如果为 0 则全是 0,如果为 1 转移方程为:
      • rowDp[i][j] = rowDp[i][j - 1] + 1
      • colDp[i][j] = colDp[i - 1][j] + 1
      • squareDp[i][j] = min(rowDp[i][j], rowDp[i][j], squareDp[i - 1][j - 1] + 1) 意为左上的正方形加上当前行、当前列可以形成的最大正方形
    • 空间压缩:rowDp 压缩后每个值等于前一个值加一(矩阵为 1),colDp 压缩后每个值等于上一轮循环当前位加一(矩阵为 1),squareDp 必须使用二维数组,因为每次遍历时会将上一行的前一位数据更新掉,同时 squareDp[i][j] = min(rowDp[i][j](当前行列), rowDp[i][j](当前行列), squareDp[i - 1][j - 1] + 1(上一行、上一列))
    • 时间复杂度:O(m*n),空间复杂度:O(n)
  • 代码
    /**
     * 动态规划+状态压缩:定义三个 dp,分别为:
     *     rowDp[i][j]:在第 i 行当前节点(含)往前连续有多少个 1
     *     colDp[i][j]:在第 j 列当前节点(含)往上连续有多少个 1
     *     squareDp[i][j]:以当前节点为右下角,连续 1 的最大正方形边长
     * 此时循环矩阵,如果为 0 则全是 0,如果为 1 转移方程为:rowDp[i][j] = rowDp[i][j - 1] + 1,colDp[i][j] = colDp[i - 1][j] + 1,
     * squareDp[i][j] = min(rowDp[i][j], rowDp[i][j], squareDp[i - 1][j - 1] + 1) 意为左上的正方形加上当前行、当前列可以形成的最大正方形
     * 空间压缩:rowDp 压缩后每个值等于前一个值加一(矩阵为 1),colDp 压缩后每个值等于上一轮循环当前位加一(矩阵为 1),
     * squareDp 必须使用二维数组,因为每次遍历时会将上一行的前一位数据更新掉,
     * 同时 squareDp[i][j] = min(rowDp[i][j](当前行列), rowDp[i][j](当前行列), squareDp[i - 1][j - 1] + 1(上一行、上一列))
     * 时间复杂度:O(m*n),空间复杂度:O(n)
     */
    public int solution(char[][] matrix) {
        // 判空
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return 0;
        }
        int m = matrix.length;
        int n = matrix[0].length;
        // 定义三个 dp,空间压缩,避免判断下标 0 可以让 dp 往后/下移动一位
        int[] rowDp = new int[n + 1];
        int[] colDp = new int[n + 1];
        // 注意必须使用二维数组,因为顺序遍历时会将上一行的前一位数据更新
        int[][] squareDp = new int[2][n + 1];
        // 循环处理三个 dp
        int res = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '0') {
                    rowDp[j + 1] = 0;
                    colDp[j + 1] = 0;
                    squareDp[i & 1][j + 1] = 0;
                } else {
                    rowDp[j + 1] = rowDp[j] + 1;
                    colDp[j + 1] = colDp[j + 1] + 1;
                    // squareDp[i][j] = min(rowDp[i][j](当前行列), rowDp[i][j](当前行列), squareDp[i - 1][j - 1] + 1(上一行、上一列))
                    squareDp[i & 1][j + 1] = Math.min(rowDp[j + 1], Math.min(colDp[j + 1], squareDp[(i + 1) & 1][j] + 1));
                    res = Math.max(res, squareDp[i & 1][j + 1]);
                }
//                System.out.print(matrix[i][j] + " : " + rowDp[j + 1] + " : " + colDp[j + 1] + " : " + squareDp[i & 1][j + 1] + "\t");
            }
//            System.out.println();
        }
        return res * res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值