【LeetCode】221. 最大正方形

leetcode

 

解题思路

最大正方形问题需要在一个由 '0' 和 '1' 组成的二维矩阵中找到全为 '1' 的最大正方形面积。通过​​动态规划​​,我们可以高效解决:

  • ​​核心思想​​:定义状态数组 dp[i][j] 表示以 (i, j) 为右下角的最大正方形边长。
  • ​​状态转移​​:当 matrix[i][j] = '1' 时,其边长受限于左、上、左上三个相邻位置的最小值(木桶原理),即:

  • ​​边界处理​​:第一行或第一列的最大边长只能是 1(无法扩展)。
  • ​​空间优化​​:使用滚动数组将空间复杂度从 O(mn) 降至 O(n)。

关键步骤

  1. ​​初始化检查​​:

    • 若矩阵为空或首元素为 '0',直接返回 0。
    • 初始化一维数组 dp(长度 = 列数+1),maxSide 记录最大边长。
  2. ​​动态规划遍历​​:

    • ​​首行初始化​​:dp[j] = 1(若 matrix[0][j]=='1'),否则为 0。
    • ​​后续行处理​​:
      • 每行首列单独处理(只能从上方继承)。
      • 非首列位置:若 matrix[i][j]=='1',则更新 dp[j] = min(左、上、左上) + 1。
    • ​​实时更新​​:maxSide = max(maxSide, dp[j])
  3. ​​结果计算​​:

    • 返回 maxSide * maxSide(面积)。

代码实现

func maximalSquare(matrix [][]byte) int {
    if len(matrix) == 0 || len(matrix[0]) == 0 {
        return 0
    }
    rows, cols := len(matrix), len(matrix[0])
    dp := make([]int, cols+1) // 多一列避免边界检查
    maxSide, prev := 0, 0     // prev 保存左上角状态

    for i := 0; i < rows; i++ {
        for j := 0; j < cols; j++ {
            temp := dp[j+1] // 保存当前状态供下一轮使用
            if matrix[i][j] == '0' {
                dp[j+1] = 0
            } else {
                // 状态转移:min(左, 上, 左上) + 1
                if i == 0 || j == 0 {
                    dp[j+1] = 1
                } else {
                    dp[j+1] = min(min(dp[j], dp[j+1]), prev) + 1
                }
                // 更新最大边长
                if dp[j+1] > maxSide {
                    maxSide = dp[j+1]
                }
            }
            prev = temp // 更新左上角状态
        }
    }
    return maxSide * maxSide
} 

示例测试

func main() {
    // 示例 1
    matrix1 := [][]byte{
        {'1', '0', '1', '0', '0'},
        {'1', '0', '1', '1', '1'},
        {'1', '1', '1', '1', '1'},
        {'1', '0', '0', '1', '0'},
    }
    fmt.Println(maximalSquare(matrix1)) // 输出: 4

    // 示例 2
    matrix2 := [][]byte{
        {'0', '1'},
        {'1', '0'},
    }
    fmt.Println(maximalSquare(matrix2)) // 输出: 1

    // 示例 3
    matrix3 := [][]byte{{'0'}}
    fmt.Println(maximalSquare(matrix3)) // 输出: 0

    // 全1矩阵
    matrix4 := [][]byte{
        {'1', '1', '1'},
        {'1', '1', '1'},
        {'1', '1', '1'},
    }
    fmt.Println(maximalSquare(matrix4)) // 输出: 9

    // 单行矩阵
    matrix5 := [][]byte{{'1', '1', '1', '1'}}
    fmt.Println(maximalSquare(matrix5)) // 输出: 1
}

复杂度分析

​​指标​​​​值​​​​说明​​
​​时间复杂度​​ O(mn) 需遍历矩阵每个元素一次(m 行,n 列)
​​空间复杂度​​ O(n) 使用一维数组 dp(长度 = 列数),优化了二维数组的 O(mn) 空间 

关键点总结

  1. ​​状态转移原理​​:

    • 正方形的扩展受限于​​三个相邻方向​​(左、上、左上)的最小值。
    • 例如:若左、上、左上的边长均为 2,则当前位置可扩展为边长 3 的正方形。
  2. ​​边界处理​​:

    • 首行/列无法扩展,直接取当前值(0 或 1)。
    • 空矩阵或首元素为 '0' 时立即返回 0,减少无效计算。
  3. ​​空间优化技巧​​:

    • ​​滚动数组​​:通过 prev 变量保存左上角状态,避免二维数组开销。
    • ​​索引偏移​​:dp 数组索引 j+1 简化边界检查。
  4. ​​失败场景处理​​:

    • 遇到 '0' 时重置 dp[j+1]=0(无法构成正方形)。
    • 最大边长初始化为 0,避免全 0 矩阵误判。
posted @ 2025-06-16 20:45  云隙之间  阅读(54)  评论(0)    收藏  举报