题目链接:https://leetcode.cn/problems/largest-submatrix-with-rearrangements/
题目描述
给定一个二进制矩阵 matrix,我们可以任意重排列矩阵的列。要求找到矩阵中全为 1 的最大子矩阵,并返回其面积。
示例 1:

输入 :matrix = [[0,0,1],[1,1,1],[1,0,1]]
输出 :4
解释 :你可以按照上图方式重新排列矩阵的每一列。
最大的全 1 子矩阵是上图中加粗的部分,面积为 4 。
解题思路
这题让我们通过改变每一列 的顺序,来构建一个尽可能大的全 1 矩形 ,而这个矩形到底在整个矩阵的哪个位置是无法确定的,但是我们只要把矩形的底边所在的行给固定,那么问题就变简单了。只需要遍历所有行然后把以该行作为底边时能够得到的所有矩形找到,总是选取最大的矩阵就行了。
因此可以用一个非常形象的方式来理解:把矩阵看成一排楼房 ,我们通过改变地基来要找出能构成的最大矩形连续房间面积。

我们可以把矩阵的每一行当作当前的地基 ,每一列看作一栋楼 。数字 1 代表这一层有楼,数字 0 代表这一层是空的。因为题目允许我们任意重排列 ,就相当于我们可以自由调换这些楼的左右顺序 ,把它们从左到右、从高到低排列,遍历每一个楼,左边所有楼都比当前楼更高或一样高,所以从最左到当前位置,一定能画出一个完整矩形
整体思路非常直观:
- 遍历每一行,把它当作新的底边。
- 维护一个高度数组,记录每栋楼当前的总层数。
- 遇到 1 就把楼层加高一层,遇到 0 就直接把这栋楼坍塌为 0 层。
- 把所有楼按高度从高到低排序,从左往右依次计算能围成的最大矩形。
- 遍历过程中不断更新最大值,最后就是答案。
算法动图

代码实现
python
class Solution:
def largestSubmatrix(self, matrix: List[List[int]]) -> int:
m,n=len(matrix),len(matrix[0])
h=[0]*n#记录当前底边上的楼层的全部高度
res=0
for row in matrix:#遍历不同的底边
for j in range(n):#遍历每栋楼楼
h[j] = h[j]+1 if row[j] == 1 else 0#遇到1就扩建,遇到0就拆除
sorted_h = sorted(h,reverse=True)#把楼层高度从高到低排列
for i in range(0,n):#i从左到右遍历每栋楼,不停增加连续楼层的总宽度(i+1)
res = max(res,sorted_h[i]*(i+1))#宽度乘当前楼高就是当前宽度能得到的最大面积,取最值
return res
代码解释
m,n=len(matrix),len(matrix[0]):获取矩阵的行数和列数。h=[0]*n:记录当前底边上,每一栋楼的楼层高度。res=0:用来保存最终的最大面积。for row in matrix:遍历每一行,把每一行当作一条新的底边。for j in range(n):遍历每一栋楼。h[j] = h[j]+1 if row[j] == 1 else 0:遇到 1 就扩建楼层,遇到 0 就直接拆除归零。sorted_h = sorted(h,reverse=True):把所有楼按高度从高到低排列,因为列可以随便换顺序。for i in range(0,n):从左到右一栋一栋看,连续的楼越来越多,宽度越来越大。res = max(res,sorted_h[i]*(i+1)):当前宽度是 i+1,当前最矮的楼决定高度,相乘就是矩形面积,不断更新最大值。- 最后返回 res 就是全 1 最大子矩阵的面积。
复杂度分析
- 时间复杂度:O(m * n log n)
遍历每一行是 O(m),更新楼层高度 O(n),每次排序 O(n log n),整体为 O(m * n log n)。 - 空间复杂度:O(n)
只使用了一个一维数组记录楼层高度,额外空间很小。
总结
这道题最巧妙的地方,就是把二维矩阵的全 1 子矩形问题,转化成了楼层柱状图 问题。
再利用题目可以重排列的条件,直接排序贪心求解,思路清晰、代码简洁,是一道非常经典的贪心与矩阵结合的好题。