【中等】力扣算法题解析LeetCode221:最大正方形

关注文末推广名片,即可免费获得本题测试源码

题目来源:LeetCode221:最大正方形

问题抽象: 在二进制矩阵中寻找全由 '1' 组成的最大正方形区域并返回其面积,需满足以下核心需求:

  1. 区域定义

    • 正方形需连续相邻(边长为 s 的正方形包含 s×s 个相邻单元格);
    • 区域内所有元素必须为 '1'(含 '0' 则无效);
    • 边界平行于矩阵边缘(非斜向)。
  2. 计算目标

    • 输出最大正方形的面积(边长平方),若不存在有效正方形则返回 0
    • 需高效处理大规模矩阵(300×300 上限)。
  3. 动态规划策略

    • 定义 dp[i][j] 表示以 (i,j)右下角的最大正方形边长
    • 状态转移:
      • matrix[i][j]=='1',则 dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
      • matrix[i][j]=='0',则 dp[i][j]=0
    • 全局最大值:max_edge = max(dp[i][j]),面积 = max_edge²
  4. 边界处理

    • 空矩阵或全 '0' 矩阵返回 0
    • 单行/单列矩阵:最大面积为 1(存在 '1' 时);
    • 初始化:首行/首列的 dp 值直接为 01(取决于 matrix 值)。

输入:二维字符矩阵 matrix(元素仅 '0''1',行数 m、列数 n ∈ [0,300]
输出:整数(最大正方形面积,值域 0min(m,n)²


解题思路

使用动态规划解决此问题,核心思想是通过状态转移方程计算以每个位置 (i, j) 为右下角的最大正方形边长。具体步骤如下:

  1. 状态定义dp[j] 表示当前行中以第 j 个元素为右下角的最大正方形边长。使用一维数组优化空间,避免二维数组的开销。
  2. 状态转移
    • 如果 matrix[i][j]'0',则 dp[j] = 0(不能构成正方形)。
    • 如果 matrix[i][j]'1',则 dp[j] 由其左侧、上方和左上方的值决定:
      [
      dp[j] = \min(dp[j-1], dp[j], pre) + 1
      ]
      其中 pre 表示上一行中第 j-1 列的值(即左上角的值)。
  3. 边界处理
    • 第一行直接初始化为对应字符的值(0 或 1)。
    • 每行的第一列单独处理(因为左侧无数据)。
  4. 更新最大边长:在动态规划过程中记录最大边长 maxSide
  5. 返回结果:最终结果为 maxSide * maxSide

代码实现(Java版)🔥点击下载源码

class Solution {
    public int maximalSquare(char[][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return 0;
        }
        int rows = matrix.length;
        int cols = matrix[0].length;
        int maxSide = 0;
        int[] dp = new int[cols]; // 一维DP数组
        
        // 初始化第一行
        for (int j = 0; j < cols; j++) {
            dp[j] = matrix[0][j] - '0'; // 字符转数字
            if (dp[j] > maxSide) {
                maxSide = dp[j]; // 更新最大边长
            }
        }
        
        // 从第二行开始动态规划
        for (int i = 1; i < rows; i++) {
            int pre = dp[0]; // 保存上一行第一列的值(作为下一列的左上角)
            // 处理当前行第一列
            dp[0] = matrix[i][0] == '1' ? 1 : 0;
            if (dp[0] > maxSide) {
                maxSide = dp[0];
            }
            // 遍历当前行剩余列
            for (int j = 1; j < cols; j++) {
                int temp = dp[j]; // 保存上一行当前列的值(用于更新pre)
                if (matrix[i][j] == '1') {
                    // 状态转移:取左、上、左上最小值加1
                    dp[j] = Math.min(Math.min(dp[j - 1], dp[j]), pre) + 1;
                    if (dp[j] > maxSide) {
                        maxSide = dp[j]; // 更新最大边长
                    }
                } else {
                    dp[j] = 0; // 当前元素为0,无法构成正方形
                }
                pre = temp; // 更新pre为上一行当前列的值
            }
        }
        
        return maxSide * maxSide; // 返回最大正方形面积
    }
}

代码说明

  1. 初始化处理

    • 检查矩阵是否为空,直接返回0。
    • 初始化 dp 数组为第一行的值('0'0'1'1),并记录最大边长 maxSide
  2. 动态规划核心

    • pre 变量:保存上一行前一列的值(即左上角的值),用于状态转移。
    • 第一列处理:每行第一列独立处理(无左侧数据),直接根据字符值设置 dp[0]
    • 状态转移
      • 若当前字符为 '1',取左侧 (dp[j-1])、上方 (dp[j]) 和左上角 (pre) 的最小值加1。
      • 若为 '0',则 dp[j] = 0
    • 更新 pre:每次迭代保存上一行当前列的值,供下一列使用。
  3. 结果计算

    • 遍历过程中持续更新 maxSide(最大边长)。
    • 返回 maxSide * maxSide(最大正方形面积)。

提交详情(执行用时、内存消耗)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

达文汐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值