You are given a binary matrix matrix of size m x n, and you are allowed to rearrange the columns of the matrix in any order.
Return the area of the largest submatrix within matrix where every element of the submatrix is 1 after reordering the columns optimally.
Example 1:
Input: matrix = [
[0,0,1],
[1,1,1],
[1,0,1]
]
Output: 3Explanation: You can rearrange the columns as shown above.
The largest submatrix of 1s, in bold, has an area of 3.
Example 2:
Input: matrix = [
[1,1,0],
[1,0,1]
]
Output: 2Explanation: Notice that you must rearrange entire columns, and there is no way to make a submatrix of 1s larger than an area of 2.
Constraints:
1 <= (matrix.length * matrix[i].length) <= 100,000matrix[i][j] is either 0 or 1.Before attempting this problem, you should be comfortable with:
We can rearrange columns in any order, so the key is to find which columns can form a rectangle of all 1s. For each starting row, we track which columns have continuous 1s from that row downward. As we extend the rectangle row by row, columns with a 0 are eliminated. The area at each step is the number of surviving columns multiplied by the current height.
0 in the current row.(remaining columns) * (current height).class Solution:
def largestSubmatrix(self, matrix: List[List[int]]) -> int:
ROWS, COLS = len(matrix), len(matrix[0])
res = 0
for start_row in range(ROWS):
ones = deque(list(range(COLS)))
for r in range(start_row, ROWS):
if not ones:
break
for _ in range(len(ones)):
c = ones.popleft()
if matrix[r][c] == 1:
ones.append(c)
res = max(res, len(ones) * (r - start_row + 1))
return resWhere is the number of rows and is the number of columns.
Think of each cell as the height of a bar extending upward through consecutive 1s. For each row, compute these heights based on the previous row. Since we can rearrange columns, sort the heights in descending order. Then greedily compute the largest rectangle: the first column can use its full height, the first two columns are limited by the second height, and so on.
heights array tracking consecutive 1s above each cell.1, add the previous height; otherwise reset to 0.i, compute area as (i + 1) * heights[i] and track the maximum.class Solution:
def largestSubmatrix(self, matrix: List[List[int]]) -> int:
ROWS, COLS = len(matrix), len(matrix[0])
res = 0
prev_heights = [0] * COLS
for r in range(ROWS):
heights = matrix[r][:]
for c in range(COLS):
if heights[c] > 0:
heights[c] += prev_heights[c]
sorted_heights = sorted(heights, reverse=True)
for i in range(COLS):
res = max(res, (i + 1) * sorted_heights[i])
prev_heights = heights
return resWhere is the number of rows and is the number of columns.
This is the same approach as above but optimizes space by modifying the input matrix directly. Each cell stores the cumulative height of consecutive 1s ending at that cell. This eliminates the need for a separate heights array.
1, add the value from the cell directly above it.class Solution:
def largestSubmatrix(self, matrix: List[List[int]]) -> int:
ROWS, COLS = len(matrix), len(matrix[0])
res = 0
for r in range(1, ROWS):
for c in range(COLS):
if matrix[r][c]:
matrix[r][c] += matrix[r - 1][c]
for r in range(ROWS):
matrix[r].sort(reverse=True)
for i in range(COLS):
res = max(res, (i + 1) * matrix[r][i])
return resWhere is the number of rows and is the number of columns.
We can avoid sorting entirely by maintaining a sorted order implicitly. Track the column indices that had continuous 1s from the previous row. For the current row, first process columns from the previous list (they have taller heights), then add new columns that just started with a 1. This naturally keeps columns ordered by height in descending order.
1s.1 (incrementing their height in the matrix).1 but was 0 before (new columns starting at height 1).i gives area (i + 1) * matrix[r][heights[i]].class Solution:
def largestSubmatrix(self, matrix: List[List[int]]) -> int:
ROWS, COLS = len(matrix), len(matrix[0])
res = 0
prevHeights = []
for r in range(ROWS):
heights = []
for c in prevHeights:
if matrix[r][c]:
matrix[r][c] += matrix[r - 1][c]
heights.append(c)
for c in range(COLS):
if matrix[r][c] == 1:
heights.append(c)
for i, c in enumerate(heights):
res = max(res, (i + 1) * matrix[r][c])
prevHeights = heights
return resWhere is the number of rows and is the number of columns.
When building the height array row by row, encountering a 0 should reset the height to 0 for that column. A common mistake is to simply add the previous height regardless of the current cell value, which incorrectly extends heights through 0 cells and produces invalid rectangles.
Unlike the standard largest rectangle in histogram problem, columns can be rearranged here. Attempting to use a monotonic stack approach without sorting the heights misses the key insight. Sorting heights in descending order allows greedy computation of the maximum area at each width.
After sorting heights in descending order, the area at position i is (i + 1) * heights[i], not i * heights[i]. The width is the number of columns considered so far (1-indexed), so using i instead of i + 1 underestimates the width by one column.