题目描述

image.png

解题思路

暴力法

由于正方形的面积等于边长的平方,因此要找到最大正方形的面积,首先需要找到最大正方形的边长,然后计算最大边长的平方即可。
暴力法是最简单直观的做法,具体做法如下:
遍历矩阵中的每个元素,每次遇到 11,则将该元素作为正方形的左上角;
确定正方形的左上角后,根据左上角所在的行和列计算可能的最大正方形的边长(正方形的范围不能超出矩阵的行数和列数),在该边长范围内寻找只包含 1 的最大正方形;
每次在下方新增一行以及在右方新增一列,判断新增的行和列是否满足所有元素都是 1。

  1. // 暴力法
  2. public int maximalSquare(char[][] matrix) {
  3. int maxSide = 0;
  4. if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
  5. return maxSide;
  6. }
  7. for (int i = 0; i < matrix.length; i++) {
  8. for (int j = 0; j < matrix[0].length; j++) {
  9. if (matrix[i][j] == '1') {
  10. // 将1作为左上角,开始搜索正方形
  11. maxSide = Math.max(maxSide, 1);
  12. // 计算可能搜索的最大边界,防止越界
  13. int maxLength = Math.min(matrix.length - i, matrix[0].length - j);
  14. for (int k = 0; k < maxLength; k++) {
  15. // 表示现在是否符合正方形
  16. // 判断新增的一行一列是否均为 1
  17. boolean flag = true;
  18. // 对角不为1,不需要搜索了
  19. if (matrix[i + k][j + k] == '0') break;
  20. for (int l = 0; l < k; l++) {
  21. if (matrix[i + l][j + k] == '0' || matrix[i + k][j + l] == '0') {
  22. // 不满足设置标志为false
  23. flag = false;
  24. break;
  25. }
  26. }
  27. if (flag) {
  28. // 更新最大边
  29. maxSide = Math.max(k + 1, maxSide);
  30. } else break;
  31. }
  32. }
  33. }
  34. }
  35. return maxSide * maxSide;
  36. }

dp

先来阐述简单共识

  • 若形成正方形(非单 1),以当前为右下角的视角看,则需要:当前格、上、左、左上都是 1
  • 可以换个角度:当前格、上、左、左上都不能受 0 的限制,才能成为正方形

image.png
这张图直接展示了当前位置的正方形边长和上,左,左上的关系,也就是取最小的加一。

dp表示的是边长,不是面积,表示面积很难求和这三者的关系。

  1. public int maximalSquare(char[][] matrix) {
  2. int maxSide = 0;
  3. if (matrix.length == 0 || matrix[0].length == 0 || matrix == null) return maxSide;
  4. // dp[i]表示:当前以i为矩形的最大边长
  5. int[][] dp = new int[matrix.length + 1][matrix[0].length + 1];
  6. // 初始化都为0
  7. for (int i = 1; i <= matrix.length; i++) {
  8. for (int j = 1; j <= matrix[0].length; j++) {
  9. if (matrix[i - 1][j - 1] == '1') {
  10. // 三者取最大
  11. dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) + 1;
  12. maxSide = Math.max(maxSide, dp[i][j]);
  13. }
  14. }
  15. }
  16. return maxSide * maxSide;
  17. }

image.png
优化
image.png

  1. // 优化
  2. public int maximalSquare(char[][] matrix) {
  3. int maxSide = 0;
  4. if (matrix.length == 0 || matrix[0].length == 0 || matrix == null) return maxSide;
  5. // dp[i]表示:当前以i为矩形的最大边长
  6. int[] dp = new int[matrix[0].length + 1];
  7. // 初始化都为0
  8. for (int i = 1; i <= matrix.length; i++) {
  9. int northwest = 0;
  10. for (int j = 1; j <= matrix[0].length; j++) {
  11. int nextNorthwest = dp[j];
  12. if (matrix[i - 1][j - 1] == '1') {
  13. // 三者取最大
  14. dp[j] = Math.min(dp[j], Math.min(dp[j - 1], northwest)) + 1;
  15. maxSide = Math.max(maxSide, dp[j]);
  16. }else dp[j] = 0;
  17. northwest = nextNorthwest;
  18. }
  19. }
  20. return maxSide * maxSide;
  21. }

image.png