leetcode:85. 最大矩形

题目

给定一个仅包含 01 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例:
[困难] 85. 最大矩形 - 图1

  1. 输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
  2. 输出:6
  3. 解释:最大矩形如上图所示。
  1. 输入:matrix = []
  2. 输出:0
  1. 输入:matrix = [["0"]]
  2. 输出:0
  1. 输入:matrix = [["1"]]
  2. 输出:1
  1. 输入:matrix = [["0","0"]]
  2. 输出:0

解答 & 代码

解法一:

  1. class Solution {
  2. public:
  3. int maximalRectangle(vector<vector<char>>& matrix) {
  4. if(matrix.size() == 0 || matrix[0].size() == 0)
  5. return 0;
  6. int rows = matrix.size();
  7. int cols = matrix[0].size();
  8. // 1. 求出矩阵中每个元素右边连续 1 的个数(包含这个元素本身),存储在 right1Len 中
  9. vector<vector<int>> right1Len(rows, vector<int>(cols, 0));
  10. for(int i = 0; i < rows; ++i)
  11. {
  12. right1Len[i][cols - 1] = matrix[i][cols - 1] == '1' ? 1 :0;
  13. for(int j = cols - 2; j >= 0; --j)
  14. right1Len[i][j] = matrix[i][j] == '0' ? 0 : right1Len[i][j + 1] + 1;
  15. }
  16. int result = 0;
  17. // 2. 遍历矩阵中每个元素,枚举以其为左下角的全 1 矩阵并计算面积
  18. for(int i = 0; i < rows; ++i)
  19. {
  20. for(int j = 0; j < cols; ++j)
  21. {
  22. if(matrix[i][j] == '1')
  23. {
  24. int width = right1Len[i][j];
  25. for(int height = 1; i - height + 1 >= 0; ++height)
  26. {
  27. width = min(width, right1Len[i - height + 1][j]);
  28. int curArea = width * height;
  29. result = max(result, curArea);
  30. }
  31. }
  32. }
  33. }
  34. return result;
  35. }
  36. };

复杂度分析:设矩阵行数为 m,列数为 n

  • 时间复杂度 [困难] 85. 最大矩形 - 图2:遍历矩阵中的每个元素,时间复杂度 O(mn)。对于每个元素,以其为全 1 矩阵左下角,往上遍历不同的高度,求所以以其为左下角的矩形面积,时间复杂度 O(m)
  • 空间复杂度 O(mn):right1Len 矩阵的空间复杂度

执行结果:

  1. 执行结果:通过
  2. 执行用时:140 ms, 在所有 C++ 提交中击败了 5.30% 的用户
  3. 内存消耗:12.6 MB, 在所有 C++ 提交中击败了 77.80% 的用户

解法二:单调栈

解法一对于矩阵中的每个元素,都要向上遍历不同的高度,求所以以其为左下角的矩形面积,增加了一个 O(m) 的时间复杂度。

  1. 求出矩阵中每个元素右边连续 1 的个数(包含这个元素本身),存储在二维矩阵 right1Len
  2. 遍历 right1Len 矩阵的每一列

    1. 单调栈,求出每个元素下边最近的比它小的元素下标,存储在 down
    2. 单调栈,求出每个元素上边最近的比它小的元素下标,存储在 up
    3. 以每个元素的值(右边连续 1 的个数)为高度,down[i] - up[i] - 1 作为宽度,求得矩形面积,与最大矩形面积比较,更新最大矩形面积

      1. class Solution {
      2. public:
      3. int maximalRectangle(vector<vector<char>>& matrix) {
      4. if(matrix.size() == 0 || matrix[0].size() == 0)
      5. return 0;
      6. int rows = matrix.size();
      7. int cols = matrix[0].size();
      8. // 1. 求出矩阵中每个元素右边连续 1 的个数(包含这个元素本身),存储在 right1Len 中
      9. vector<vector<int>> right1Len(rows, vector<int>(cols, 0));
      10. for(int i = 0; i < rows; ++i)
      11. {
      12. right1Len[i][cols - 1] = matrix[i][cols - 1] == '1' ? 1 :0;
      13. for(int j = cols - 2; j >= 0; --j)
      14. right1Len[i][j] = matrix[i][j] == '0' ? 0 : right1Len[i][j + 1] + 1;
      15. }
      16. int result = 0;
      17. // 2. 遍历 right1Len 矩阵的每一列
      18. for(int j = 0; j < cols; ++j)
      19. {
      20. // 2.1 单调栈,求出每个元素下边最近的比它小的元素下标,存储在 down
      21. vector<int> down(rows, 0);
      22. stack<int> s;
      23. for(int i = rows - 1; i >= 0; --i) // 从下往上便利
      24. {
      25. while(!s.empty() && right1Len[s.top()][j] >= right1Len[i][j])
      26. s.pop();
      27. down[i] = s.empty() ? rows : s.top();
      28. s.push(i);
      29. }
      30. // 2.2 单调栈,求出每个元素上边最近的比它小的元素下标,存储在 up
      31. vector<int> up(rows, 0);
      32. while(!s.empty())
      33. s.pop();
      34. for(int i = 0; i < rows; ++i) // 从上往下遍历
      35. {
      36. while(!s.empty() && right1Len[s.top()][j] >= right1Len[i][j])
      37. s.pop();
      38. up[i] = s.empty() ? -1 : s.top();
      39. s.push(i);
      40. }
      41. // 2.3 以每个元素的值(右边连续 1 的个数)为高度,down[i] - up[i] - 1 作为宽度
      42. // 求得矩形面积,与最大矩形面积比较,更新最大矩形面积
      43. for(int i = 0; i < rows; ++i)
      44. {
      45. int height = right1Len[i][j];
      46. int width = down[i] - up[i] - 1;
      47. int curArea = height * width;
      48. // cout << "i = " << i << ", j = " << j << ": height = " << height << ", down[i] = " << down[i] << ", up[i] = " << up[i] << ", curArea = " << curArea << endl;
      49. result = max(result, curArea);
      50. }
      51. }
      52. return result;
      53. }
      54. };

      复杂度分析:设矩阵行数为 m,列数为 n

  • 时间复杂度 [困难] 85. 最大矩形 - 图3:遍历矩阵中的一列,时间复杂度 O(n)。然后对每一列的每一个元素,用单调栈求其下方最近的比它小的位置,求其上方最近的比它小的位置,再分别以每个元素为高度求最大矩形面积,三个操作的时间复杂度都为 O(m)
  • 空间复杂度 O(mn):right1Len 矩阵的空间复杂度

执行结果:

  1. 执行结果:通过
  2. 执行用时:44 ms, 在所有 C++ 提交中击败了 53.31% 的用户
  3. 内存消耗:15.1 MB, 在所有 C++ 提交中击败了 28.38% 的用户