Medium
题目描述
给你一个大小为 m x n 的二进制矩阵 matrix,你可以任意重新排列矩阵的列。
在最优地重新排列列后,返回 matrix 中全部元素都是 1 的最大子矩阵的面积。
示例 1:
输入:matrix = [[0,0,1],[1,1,1],[1,0,1]]
输出:4
解释:你可以按如上所示重新排列列。
全部元素都是 1 的最大子矩阵(用粗体标出)的面积为 4。
示例 2:
输入:matrix = [[1,0,1,0,1]]
输出:3
解释:你可以按如上所示重新排列列。
全部元素都是 1 的最大子矩阵(用粗体标出)的面积为 3。
示例 3:
输入:matrix = [[1,1,0],[1,0,1]]
输出:2
解释:注意你必须重新排列整个列,没有办法让全部元素都是 1 的子矩阵面积超过 2。
提示:
m == matrix.lengthn == matrix[i].length1 <= m * n <= 10^5matrix[i][j]要么是 0,要么是 1
提示:
- 对于每一列,找到每个位置结尾的连续 1 的数量。
- 对于每一行,将累计的 1 按非递增顺序排序,并"适合"最大的子矩阵。
解题思路
这道题的关键洞察是:由于我们可以任意重新排列列,所以对于固定的行作为矩形底边,我们要找的是在这一行上能形成的最大矩形面积。
解题思路:
预处理阶段:对于每一列,计算从上往下每个位置结尾的连续1的个数(即高度)。如果当前位置是0,则高度为0;如果是1,则高度为上一行该列的高度+1。
贪心策略:对于每一行,我们获得了该行每列对应的"高度"数组。由于可以任意重排列,我们将高度数组按降序排序。
计算最大面积:排序后,对于位置i(0-indexed),我们可以取前i+1个柱子组成矩形,高度为第i个柱子的高度,宽度为i+1。遍历所有可能的宽度,取最大面积。
这个算法的核心思想是将问题转化为"柱状图中的最大矩形"变种。通过重排列的特性,我们可以贪心地选择最优的列组合。
时间复杂度为O(m×n×log n),空间复杂度为O(n)。
代码实现
class Solution {
public:
int largestSubmatrix(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
int maxArea = 0;
// 计算每列从上到下的连续1的高度
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];
}
}
}
// 对每一行进行处理
for (int i = 0; i < m; i++) {
vector<int> heights = matrix[i];
sort(heights.begin(), heights.end(), greater<int>());
for (int j = 0; j < n; j++) {
maxArea = max(maxArea, heights[j] * (j + 1));
}
}
return maxArea;
}
};
class Solution:
def largestSubmatrix(self, matrix: List[List[int]]) -> int:
m, n = len(matrix), len(matrix[0])
max_area = 0
# 计算每列从上到下的连续1的高度
for i in range(1, m):
for j in range(n):
if matrix[i][j] == 1:
matrix[i][j] += matrix[i-1][j]
# 对每一行进行处理
for i in range(m):
heights = matrix[i][:]
heights.sort(reverse=True)
for j in range(n):
max_area = max(max_area, heights[j] * (j + 1))
return max_area
public class Solution {
public int LargestSubmatrix(int[][] matrix) {
int m = matrix.Length, n = matrix[0].Length;
int maxArea = 0;
// 计算每列从上到下的连续1的高度
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];
}
}
}
// 对每一行进行处理
for (int i = 0; i < m; i++) {
int[] heights = new int[n];
Array.Copy(matrix[i], heights, n);
Array.Sort(heights, (a, b) => b.CompareTo(a));
for (int j = 0; j < n; j++) {
maxArea = Math.Max(maxArea, heights[j] * (j + 1));
}
}
return maxArea;
}
}
/**
* @param {number[][]} matrix
* @return {number}
*/
var largestSubmatrix = function(matrix) {
const m = matrix.length;
const n = matrix[0].length;
// Calculate heights for each position
for (let i = 1; i < m; i++) {
for (let j = 0; j < n; j++) {
if (matrix[i][j] === 1) {
matrix[i][j] += matrix[i-1][j];
}
}
}
let maxArea = 0;
// For each row, sort heights and calculate max area
for (let i = 0; i < m; i++) {
const heights = matrix[i].slice().sort((a, b) => b - a);
for (let j = 0; j < n; j++) {
const area = heights[j] * (j + 1);
maxArea = Math.max(maxArea, area);
}
}
return maxArea;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(m × n × log n) | 预处理需要O(m×n),每行排序需要O(n log n),共m行 |
| 空间复杂度 | O(n) | 需要额外数组存储每行的高度进行排序 |
相关题目
- . Max Area of Island (Medium)