题目
标题和出处
标题:重新排列后的最大子矩阵
难度
7 级
题目描述
要求
给定一个大小为 m × n \texttt{m} \times \texttt{n} m×n 的二进制矩阵 matrix \texttt{matrix} matrix,可以将 matrix \texttt{matrix} matrix 中的列按任意顺序重新排列。
返回将 matrix \texttt{matrix} matrix 按照最优方案重新排列后,全是 1 \texttt{1} 1 的最大子矩阵面积。
示例
示例 1:
输入:
matrix
=
[[0,0,1],[1,1,1],[1,0,1]]
\texttt{matrix = [[0,0,1],[1,1,1],[1,0,1]]}
matrix = [[0,0,1],[1,1,1],[1,0,1]]
输出:
4
\texttt{4}
4
解释:可以按照上图方式重新排列矩阵的每一列。最大的全
1
\texttt{1}
1 子矩阵是上图中加粗的部分,面积为
4
\texttt{4}
4。
示例 2:
输入:
matrix
=
[[1,0,1,0,1]]
\texttt{matrix = [[1,0,1,0,1]]}
matrix = [[1,0,1,0,1]]
输出:
3
\texttt{3}
3
解释:可以按照上图方式重新排列矩阵的每一列。最大的全
1
\texttt{1}
1 子矩阵是上图中加粗的部分,面积为
3
\texttt{3}
3。
示例 3:
输入:
matrix
=
[[1,1,0],[1,0,1]]
\texttt{matrix = [[1,1,0],[1,0,1]]}
matrix = [[1,1,0],[1,0,1]]
输出:
2
\texttt{2}
2
解释:由于只能按整列重新排布,所以没有比面积为
2
\texttt{2}
2 更大的全
1
\texttt{1}
1 子矩形。
数据范围
- m = matrix.length \texttt{m} = \texttt{matrix.length} m=matrix.length
- n = matrix[i].length \texttt{n} = \texttt{matrix[i].length} n=matrix[i].length
- 1 ≤ m × n ≤ 10 5 \texttt{1} \le \texttt{m} \times \texttt{n} \le \texttt{10}^\texttt{5} 1≤m×n≤105
- matrix[i][j] \texttt{matrix[i][j]} matrix[i][j] 是 0 \texttt{0} 0 或 1 \texttt{1} 1
解法
思路和算法
由于对矩阵重新排列的规则是按整列重新排列,因此可以对矩阵的每一列做预处理,对于每个元素 1 1 1,计算该元素向上的最大连续 1 1 1 的个数,然后即可单独处理矩阵的每一行。
经过预处理之后,矩阵中的每个元素更新为该元素向上的最大连续 1 1 1 的个数。如果更新后的矩阵中,某一行有 x x x 个元素不小于 y y y( x x x 和 y y y 都是正整数),则说明可以将原矩阵重新排列,使得重新排列的矩阵中存在一个以该行为底边的全 1 1 1 子矩阵,该子矩阵的宽度是 x x x,高度是 y y y,面积是 x y xy xy。
为了得到最大全 1 1 1 子矩阵的面积,可以将更新后的矩阵的每一行排序,然后对矩阵的每一行按照从大到小的顺序遍历,计算以该行为底边的最大全 1 1 1 子矩阵面积。
对于矩阵的某一行,假设第 k k k 大的元素是 val k \textit{val}_k valk( k ≥ 1 k \ge 1 k≥1),则该行有至少 k k k 个元素不小于 val k \textit{val}_k valk, k k k 个最大元素组成的全 1 1 1 子矩阵面积是 val k × k \textit{val}_k \times k valk×k。从大到小遍历该行的每个元素,当元素大于 0 0 0 时使用元素值与元素的排序编号(第 k k k 大的元素的排序编号是 k k k)计算全 1 1 1 子矩阵面积,并维护最大全 1 1 1 子矩阵面积。当遍历到等于 0 0 0 的元素时,该行剩余的元素都是 0 0 0,该行内不可能再遇到全 1 1 1 子矩阵,因此结束遍历该行。
遍历更新后的矩阵的每一行之后,即可得到最大全 1 1 1 子矩阵面积。
代码
class Solution {
public int largestSubmatrix(int[][] matrix) {
int maxArea = 0;
int m = matrix.length, n = matrix[0].length;
for (int i = 1; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 1) {
matrix[i][j] = matrix[i - 1][j] + 1;
}
}
}
for (int i = 0; i < m; i++) {
int[] row = matrix[i];
Arrays.sort(row);
for (int j = n - 1, k = 1; j >= 0 && row[j] > 0; j--, k++) {
int area = row[j] * k;
maxArea = Math.max(maxArea, area);
}
}
return maxArea;
}
}
复杂度分析
-
时间复杂度: O ( m n log n ) O(mn \log n) O(mnlogn),其中 m m m 和 n n n 分别是矩阵 matrix \textit{matrix} matrix 的行数和列数。遍历并更新矩阵需要 O ( m n ) O(mn) O(mn) 的时间,对更新后的矩阵的每一行排序共需要 O ( m n log n ) O(mn \log n) O(mnlogn) 的时间,计算最大面积需要 O ( m n ) O(mn) O(mn) 的时间,时间复杂度是 O ( m n log n ) O(mn \log n) O(mnlogn)。
-
空间复杂度: O ( log n ) O(\log n) O(logn),其中 n n n 是矩阵 matrix \textit{matrix} matrix 的列数。对更新后的矩阵的每一行排序需要 O ( log n ) O(\log n) O(logn) 的递归调用栈空间。