与动态规划的爱恨情仇——最大正方形

64 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情


最近一直在力扣刷题,也逐渐对各类题型有了自己的理解,所谓见招拆招,将自己的浅显经验分享一下,帮助更多在编程路上的朋友们。


最大正方形

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

 

示例 1:

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

示例 2:

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

示例 3:

输入: matrix = [["0"]]
输出: 0

 

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 300
  • matrix[i][j] 为 '0' 或 '1'

思路

题目要求找到最大的正方形面积,我们只需要找到最大的正方形边长即可,最后返回边长的平方。

遍历一次二维数组就需要O(mn)的时间复杂度,如果对每一个点进行遍历,再根据该点寻找最长的边长,则时间复杂度会更大,虽然测试用例中 m 和 n 的数据量很小,但暴力法能不用就尽量不要用。我们可以发现前一状态的边长长度是可以保存的,故采用动态规划的方法。

dp[i][j]代表以(i, j)为右下角正方形的最大边长。

对于(i, j)位置,如果matrix[i][j] == '1',则该位置的最大边长由左、左上、上方向的三个相邻位置的最大边长决定的。取三个位置中的最小边长 + 1 即为该位置的最大边长。状态转移方程为dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) + 1

题解

class Solution {
    public int maximalSquare(char[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        int[][] dp = new int[m + 1][n + 1];
        int max = 0;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                if(matrix[i][j] == '1') {
                    dp[i + 1][j + 1] = Math.min(dp[i + 1][j], Math.min(dp[i][j + 1], dp[i][j])) + 1;
                    max = Math.max(dp[i + 1][j + 1], max);
                }
            }
        }
        return max * max;
    }
}