题目描述
Problem: 剑指 Offer II 040. 矩阵中最大的矩形
文章目录
- 题目描述
- 解法一:暴力解法
- 思路
- 解题方法
- 复杂度
- Code
- 解法二:单调栈解法
解法一:暴力解法
思路
首先, 按行获取到达某一元素位置时,之前与当前连续1的个数,这个连续1的个数就会作为所求矩阵的备选宽度。然后, 再迭代遍历,以列不变的基础上,向上改变行的位置,将原始位置与改变位置之差作为目标矩阵的备选长度,最后求得最大矩阵面积。
解题方法
计算矩阵宽度时,先以当前位置连续1的个数作为宽度,在后续更新时,因为要保证这个矩阵范围内都可以被囊括,就以迭代遍历中的最小宽度作为矩阵宽度。
计算矩阵面积时,用宽度乘以当前遍历到的行数之差,找出和已有结果对比的最大值,作为最大面积。
复杂度
- 时间复杂度:
O ( m 2 n ) O(m^2n) O(m2n)
其中 m 和 n 分别是矩阵的行数和列数。计算 left 矩阵需要 O ( m n ) O(mn) O(mn)的时间。随后对于矩阵的每个点,需要 O(m) 的时间枚举高度。故总的时间复杂度为 O ( m n ) + O ( m n ) ⋅ O ( m ) = O ( m 2 n ) O(mn)+O(mn)⋅O(m)=O(m^2n) O(mn)+O(mn)⋅O(m)=O(m2n)。
- 空间复杂度:
O ( m n ) O(mn) O(mn)
其中 m 和 n 分别是矩阵的行数和列数。我们分配了一个与给定矩阵等大的数组,用于存储每个元素的左边连续 1 的数量。
Code
C++
class Solution {
public:
int maximalRectangle(vector<string>& matrix) {
int m = matrix.size();
if(m == 0) return 0;
int n = matrix[0].size();
vector<vector<int>> left(m, vector<int>(n, 0));
for(int i = 0; i < m; i++) { // 记录每行中连续1的个数
for(int j = 0; j < n; j++) {
if(matrix[i][j] == '1') {
left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
}
}
}
int res = 0;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(matrix[i][j] == '0') { // 遇到0说明不是矩阵,则直接跳出
continue;
}
int width = left[i][j];
int area = width; // 此时的面积是以长度=1,宽度=left[i][j],得到的面积
for(int k = i - 1; k >= 0; k--) { // 因为之前记录的是每行连续的1(也就是长度),因此这里需要变化的是的整体的行长(宽度),从i-1开始
width = min(width, left[k][j]); // 找到当前范围内的最小宽度,遍历每种范围内的情况
area = max(area, (i - k + 1) * width); // 获取当列不变时,行从0~i之间的最大面积
}
res = max(res, area); // 找到整体的最大面积
}
}
return res;
}
};
Python
class Solution:
def maximalRectangle(self, matrix: List[str]) -> int:
m = len(matrix)
if m == 0:
return 0
n = len(matrix[0])
left = [[0 for _ in range(n)] for _ in range(m)]
res = 0
for i in range(m):
for j in range(n):
if matrix[i][j] == '1':
left[i][j] = left[i][j - 1] + 1 if j != 0 else 1
for i in range(m):
for j in range(n):
width, area = left[i][j], left[i][j]
for k in range(i - 1, -1, -1):
width = min(width, left[k][j])
area = max(area, (i - k + 1) * width)
res = max(res, area)
return res
参考文章:矩阵中最大的矩形