leetcode 221. Maximal Square | 221. 最大正方形(优化的暴力解法+动态规划解法)

蔚落 2022-10-07 12:57 285阅读 0赞

题目

https://leetcode.com/problems/maximal-square/
在这里插入图片描述

题解

方法1:最暴力解 O((m*n)^2)

在这里插入图片描述

  1. public class Solution {
  2. public int maximalSquare(char[][] matrix) {
  3. int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0;
  4. int maxsqlen = 0;
  5. for (int i = 0; i < rows; i++) {
  6. for (int j = 0; j < cols; j++) {
  7. if (matrix[i][j] == '1') {
  8. int sqlen = 1;
  9. boolean flag = true;
  10. while (sqlen + i < rows && sqlen + j < cols && flag) {
  11. for (int k = j; k <= sqlen + j; k++) {
  12. if (matrix[i + sqlen][k] == '0') {
  13. flag = false;
  14. break;
  15. }
  16. }
  17. for (int k = i; k <= sqlen + i; k++) {
  18. if (matrix[k][j + sqlen] == '0') {
  19. flag = false;
  20. break;
  21. }
  22. }
  23. if (flag)
  24. sqlen++;
  25. }
  26. if (maxsqlen < sqlen) {
  27. maxsqlen = sqlen;
  28. }
  29. }
  30. }
  31. }
  32. return maxsqlen * maxsqlen;
  33. }
  34. }

方法2:优化的暴力解法 O((m^2)*n)

在这里插入图片描述
在这里插入图片描述
虽然时间复杂度相同,但本代码没有实现上述“只看4个点”,此处待改进…

  1. class Solution {
  2. public int maximalSquare(char[][] matrix) {
  3. int[][] right = new int[matrix.length][matrix[0].length]; // 向右有多少个连续的1
  4. int[][] down = new int[matrix.length][matrix[0].length]; // 向下有多少个连续的1
  5. // right
  6. for (int i = matrix.length - 1; i >= 0; i--) {
  7. int count = 0;
  8. for (int j = matrix[0].length - 1; j >= 0; j--) {
  9. if (matrix[i][j] == '0') count = 0;
  10. else count++;
  11. right[i][j] = count;
  12. }
  13. }
  14. // down
  15. for (int i = matrix[0].length - 1; i >= 0; i--) {
  16. int count = 0;
  17. for (int j = matrix.length - 1; j >= 0; j--) {
  18. if (matrix[j][i] == '0') count = 0;
  19. else count++;
  20. down[j][i] = count;
  21. }
  22. }
  23. // check
  24. int area = 0;
  25. for (int i = 0; i < matrix.length; i++) {
  26. for (int j = 0; j < matrix[0].length; j++) {
  27. if (right[i][j] > 0) {
  28. int square = right[i][j]; // 正方形最大边长
  29. for (int k = 0; k < right[i][j]; k++) {
  30. square = Math.min(square, down[i][j + k]); // 最大边长要取min 因为受向下连续1个数的限制
  31. area = Math.max(area, Math.min((k + 1) * (k + 1), square * square)); // 最大面积要取min 因为受到起点k的距离的限制
  32. }
  33. }
  34. }
  35. }
  36. return area;
  37. }
  38. }

在这里插入图片描述

附:左神算法配套代码,实现了上述“只看4个点”,供参考。

  1. package chapter_8_arrayandmatrix;
  2. public class Problem_21_MaxOneBorderSize {
  3. public static void setBorderMap(int[][] m, int[][] right, int[][] down) {
  4. int r = m.length;
  5. int c = m[0].length;
  6. if (m[r - 1][c - 1] == 1) {
  7. right[r - 1][c - 1] = 1;
  8. down[r - 1][c - 1] = 1;
  9. }
  10. for (int i = r - 2; i != -1; i--) {
  11. if (m[i][c - 1] == 1) {
  12. right[i][c - 1] = 1;
  13. down[i][c - 1] = down[i + 1][c - 1] + 1;
  14. }
  15. }
  16. for (int i = c - 2; i != -1; i--) {
  17. if (m[r - 1][i] == 1) {
  18. right[r - 1][i] = right[r - 1][i + 1] + 1;
  19. down[r - 1][i] = 1;
  20. }
  21. }
  22. for (int i = r - 2; i != -1; i--) {
  23. for (int j = c - 2; j != -1; j--) {
  24. if (m[i][j] == 1) {
  25. right[i][j] = right[i][j + 1] + 1;
  26. down[i][j] = down[i + 1][j] + 1;
  27. }
  28. }
  29. }
  30. }
  31. public static int getMaxSize(int[][] m) {
  32. int[][] right = new int[m.length][m[0].length];
  33. int[][] down = new int[m.length][m[0].length];
  34. setBorderMap(m, right, down);
  35. for (int size = Math.min(m.length, m[0].length); size != 0; size--) {
  36. if (hasSizeOfBorder(size, right, down)) {
  37. return size;
  38. }
  39. }
  40. return 0;
  41. }
  42. public static boolean hasSizeOfBorder(int size, int[][] right, int[][] down) {
  43. for (int i = 0; i != right.length - size + 1; i++) {
  44. for (int j = 0; j != right[0].length - size + 1; j++) {
  45. if (right[i][j] >= size && down[i][j] >= size
  46. && right[i + size - 1][j] >= size
  47. && down[i][j + size - 1] >= size) {
  48. return true;
  49. }
  50. }
  51. }
  52. return false;
  53. }
  54. public static int[][] generateRandom01Matrix(int rowSize, int colSize) {
  55. int[][] res = new int[rowSize][colSize];
  56. for (int i = 0; i != rowSize; i++) {
  57. for (int j = 0; j != colSize; j++) {
  58. res[i][j] = (int) (Math.random() * 2);
  59. }
  60. }
  61. return res;
  62. }
  63. public static void printMatrix(int[][] matrix) {
  64. for (int i = 0; i != matrix.length; i++) {
  65. for (int j = 0; j != matrix[0].length; j++) {
  66. System.out.print(matrix[i][j] + " ");
  67. }
  68. System.out.println();
  69. }
  70. }
  71. public static void main(String[] args) {
  72. int[][] matrix = generateRandom01Matrix(7, 8);
  73. printMatrix(matrix);
  74. System.out.println(getMaxSize(matrix));
  75. }
  76. }

方法3:动态规划

思路来源:leetcode 官方题解
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

动态规划最重要的就是想清楚 d[i,j] 代表着什么,这个太重要了。

这道题中的 d[i, j] 代表的是,以坐标点(i,j) 为右下角的最大正方形,如果说你的 d[i,j] 是想这个区域中最大的正方形,那可就麻烦太多了。

官方题解代码:

  1. public class Solution {
  2. public int maximalSquare(char[][] matrix) {
  3. int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0;
  4. int[][] dp = new int[rows + 1][cols + 1];
  5. int maxsqlen = 0;
  6. for (int i = 1; i <= rows; i++) {
  7. for (int j = 1; j <= cols; j++) {
  8. if (matrix[i-1][j-1] == '1'){
  9. dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
  10. maxsqlen = Math.max(maxsqlen, dp[i][j]);
  11. }
  12. }
  13. }
  14. return maxsqlen * maxsqlen;
  15. }
  16. }

方法4:动态规划的优化解法

在这里插入图片描述

  1. public class Solution {
  2. public int maximalSquare(char[][] matrix) {
  3. int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0;
  4. int[] dp = new int[cols + 1];
  5. int maxsqlen = 0, prev = 0;
  6. for (int i = 1; i <= rows; i++) {
  7. for (int j = 1; j <= cols; j++) {
  8. int temp = dp[j];
  9. if (matrix[i - 1][j - 1] == '1') {
  10. dp[j] = Math.min(Math.min(dp[j - 1], prev), dp[j]) + 1;
  11. maxsqlen = Math.max(maxsqlen, dp[j]);
  12. } else {
  13. dp[j] = 0;
  14. }
  15. prev = temp;
  16. }
  17. }
  18. return maxsqlen * maxsqlen;
  19. }
  20. }

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,285人围观)

还没有评论,来说两句吧...

相关阅读