leetcode85:Maximal Rectangle

柔光的暖阳◎ 2022-05-11 14:38 309阅读 0赞

Given a 2D binary matrix filled with 0’s and 1’s, find the largest rectangle containing only 1’s and return its area.

Example:

  1. Input:
  2. [
  3. ["1","0","1","0","0"],
  4. ["1","0","1","1","1"],
  5. ["1","1","1","1","1"],
  6. ["1","0","0","1","0"]
  7. ]
  8. Output: 6

求01矩阵中最大的子矩阵,这个子矩阵中全部是1.

题意还是比较简单的,感觉比较有意思,就自己做了一下。

方法1 O(n^4):

开始考虑的是利用二维前缀和(sum[i][j]代表从左上角是0,0 右下角是i,j组成的矩形中的1的个数),这样再分别枚举矩形的左上角和右下角,当左上角和右下角组成的矩形的前缀和和等于其坐标面积时,表明这个矩形里面全部是1,不断更新答案,最后肯定能算出最大的矩形面积。假设左上角的坐标x,y,右下角的坐标i,j,那么其组成的矩形前缀和计算可以用sum[i][j] - sum[x-1][y] - sum[x][y-1] + sum[x-1][y-1]表示。这里因为要枚举两个点,每个点要两个参数确定,因此复杂度是O(n^4),明显不像是最优解。

方法2 O(n^3):

后面想到以前做过二维矩阵中求和最大的子矩阵,跟这题类似。我们可以将矩阵中的1视为1,但是0要视为比较小的值,比如-1e8。这样的话用最大和子矩阵来求解,最终的结果中肯定不会包含0点,因为包含的话会导致总和急剧减少。我们可以利用这种方法来将其转换成最大子矩阵的问题。

最大子矩阵:一维的连续最大和比较简单,在遍历数组时,累计前缀和sum,当sum小于0时,我们完全可以丢弃前面的部分,将sum变为0,当sum大于0时, 我们更新答案。这样一维连续最大和的复杂度是O(N)。到二维情况,我们可以将每一列压缩,每一列计算前缀和,当需要第i行和第k行之间的所有列的压缩值时,可以利用之前计算的前缀和计算:sum[k][j] - sum[i-1][j]。最后我们枚举行,开始i结束k,对于每个i和k,都用一维计算最大连续和的方法,此时列已经被压缩,计算的最大连续和其实也就是二维中的最大子矩阵。

方法3:O(n^2):

之前已经学会求直方图中的最大矩形(链接),现在可以将这个问题利用列的前缀和计算一下,就变成了一样的问题,不过我们需要在每一行上都计算一次,因为每列上的直方图不是从统一的一行开始的。

将每一列计算前缀和,然后在每一行上,进行一次复杂度是O(n)的直方图中最大矩阵的计算。这样总的复杂度是O(N^2)。

方法2代码:O(n^3)

  1. //方法2:O(n^3)
  2. func maximalRectangle(matrix [][]byte) int {
  3. var n int
  4. if n = len(matrix); n == 0 {
  5. return 0
  6. }
  7. m := len(matrix[0])
  8. // var sum [][]int
  9. // for i:=0; i<n; i++ {
  10. // m := len(matrix[i])
  11. // tmp := make([]int, m)
  12. // add := 0
  13. // for j:=m-1; j>=0 ; j-- {
  14. // if string(matrix[i][j]) == "1" { //todo
  15. // add += 1
  16. // } else {
  17. // add = 0
  18. // }
  19. // tmp[j] = add
  20. // }
  21. // sum = append(sum, tmp)
  22. // }
  23. var sum[][]int
  24. for i := 0; i < n; i++ {
  25. tmp := make([]int, m)
  26. sum = append(sum, tmp)
  27. }
  28. for j := 0; j < m; j++ {
  29. add := 0
  30. for i := 0; i < n; i++ {
  31. if matrix[i][j] == '1' {
  32. add += 1
  33. } else {
  34. add -= 1000000
  35. }
  36. sum[i][j] = add
  37. }
  38. }
  39. ans := 0
  40. for i := 0; i < n; i++ {
  41. for j := i; j < n; j++ {
  42. updateAnswer(sum, i, j, m, &ans)
  43. }
  44. }
  45. return ans
  46. }
  47. func updateAnswer(sum [][]int, start, end, m int, ans *int) {
  48. ret := 0
  49. for j := 0; j < m; j++ {
  50. nowValue := 0
  51. if start == 0 {
  52. nowValue = sum[end][j]
  53. } else {
  54. nowValue = sum[end][j] - sum[start - 1][j]
  55. }
  56. ret += nowValue
  57. if ret > *ans {
  58. *ans = ret
  59. } else if ret < 0 {
  60. ret = 0
  61. }
  62. }
  63. }

方法3代码:O(n^2)

  1. //方法3:O(n^2)
  2. func maximalRectangle(matrix [][]byte) int {
  3. var n int
  4. if n = len(matrix); n == 0 {
  5. return 0
  6. }
  7. m := len(matrix[0])
  8. var sum[][]int
  9. for i := 0; i < n; i++ {
  10. tmp := make([]int, m)
  11. sum = append(sum, tmp)
  12. }
  13. for j := 0; j < m; j++ {
  14. add := 0
  15. for i := 0; i < n; i++ {
  16. if matrix[i][j] == '1' {
  17. add += 1
  18. } else {
  19. add = 0
  20. }
  21. sum[i][j] = add
  22. }
  23. }
  24. ans := 0
  25. for i := 0; i < n; i++ {
  26. calMaxRectangle(sum[i], m, &ans)
  27. }
  28. return ans
  29. }
  30. func calMaxRectangle(sum []int, m int, ans *int) {
  31. s := make([]int, m)
  32. for j := 0; j < m; j++ {
  33. if len(s) == 0 || sum[j] >= sum[s[len(s) - 1]] {
  34. s = append(s, j)
  35. continue
  36. }
  37. for {
  38. height := sum[s[len(s) - 1]]
  39. s = s[:len(s) - 1]
  40. if len(s) == 0 {
  41. if *ans < height * j {
  42. *ans = height * j
  43. fmt.Printf("height == %v, j == %v\n", height, j)
  44. }
  45. break
  46. }
  47. width := j - s[len(s) - 1] - 1
  48. if height * width > *ans {
  49. *ans = height * width
  50. }
  51. if sum[s[len(s) - 1]] <= sum[j] {
  52. break
  53. }
  54. }
  55. j--
  56. }
  57. fmt.Println("here")
  58. for {
  59. height := sum[s[len(s) - 1]]
  60. s = s[:len(s) - 1]
  61. if len(s) == 0 { //最后一个元素出栈
  62. if *ans < height * m {
  63. *ans = height * m
  64. fmt.Printf("height == %v, m == %v\n", height, m)
  65. }
  66. break
  67. }
  68. width := m - s[len(s) - 1] - 1
  69. if height * width > *ans {
  70. *ans = height * width
  71. }
  72. }
  73. fmt.Printf("ans == %v\n", *ans)
  74. }

发表评论

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

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

相关阅读