Given an m x n matrix of integers matrix, if an element is 0, set its entire row and column to 0's.
You must update the matrix in-place.
Follow up: Could you solve it using O(1) space?
Example 1:
Input: matrix = [
[0,1],
[1,0]
]
Output: [
[0,0],
[0,0]
]Example 2:
Input: matrix = [
[1,2,3],
[4,0,5],
[6,7,8]
]
Output: [
[1,0,3],
[0,0,0],
[6,0,8]
]Constraints:
1 <= matrix.length, matrix[0].length <= 100-2^31 <= matrix[i][j] <= (2^31) - 1
You should aim for a solution with O(m*n) time and O(1) space, where m is the number of rows and n is the number of columns in the given matrix.
A brute force approach would iterate through the given matrix and update the corresponding row and column in a new matrix on the fly. This would result in an O((m*n)*(m+n)) time and O(m*n) space solution. Can you think of a better way? Maybe you should consider using a single variable for a row and a single variable for a column instead of updating entire row and column.
A better approach is to use O(m+n) boolean arrays. We iterate through the matrix, and when encountering a zero, we mark the respective row and column as true. In the second iteration, we set a cell to 0 if its corresponding row or column is marked true. Can you think of a way to optimize the space further?
We can use the topmost row and leftmost column of the matrix as boolean arrays by marking 0 instead of true. However, since they overlap at one cell, we use a single variable to track the top row separately. We then iterate through the matrix and mark zeros accordingly.
In the second iteration, we update all cells that are not part of the top row or left column accordingly. After making the necessary changes, we check the top-leftmost cell and update the corresponding column. Finally, we check the extra variable and update the top row accordingly.
Before attempting this problem, you should be comfortable with:
We need to modify the matrix so that if any cell is 0, then its entire row and entire column become 0.
The main challenge is that if we change cells to 0 while scanning, those newly created zeros could incorrectly force more rows/columns to be zeroed.
To avoid this, the brute force approach uses a separate copy of the matrix:
This keeps the logic simple and prevents accidental cascading updates.
ROWS and COLS be the matrix dimensions.mark with the same values as the original matrix.(r, c) in the original matrix:matrix[r][c] == 0:r of mark to 0c of mark to 0mark back into matrix.matrix is now updated correctly.class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
ROWS, COLS = len(matrix), len(matrix[0])
mark = [[matrix[r][c] for c in range(COLS)] for r in range(ROWS)]
for r in range(ROWS):
for c in range(COLS):
if matrix[r][c] == 0:
for col in range(COLS):
mark[r][col] = 0
for row in range(ROWS):
mark[row][c] = 0
for r in range(ROWS):
for c in range(COLS):
matrix[r][c] = mark[r][c]Where is the number of rows and is the number of columns.
We need to update the matrix so that if a cell is 0, then its entire row and entire column are set to 0.
The key challenge is to avoid modifying the matrix too early.
If we directly set rows and columns to 0 while scanning, newly created zeros could incorrectly trigger more rows and columns to be zeroed.
To handle this safely, we split the process into two passes:
rows and cols flagsWe use two helper arrays:
rows[r] → whether row r should be zeroedcols[c] → whether column c should be zeroedThis keeps the logic clean and easy to reason about.
ROWS and COLS be the dimensions of the matrix.rows of size ROWS, initialized to falsecols of size COLS, initialized to falsematrix[r][c] == 0:rows[r] = truecols[c] = truerows[r] is true or cols[c] is true:matrix[r][c] = 0class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
ROWS, COLS = len(matrix), len(matrix[0])
rows, cols = [False] * ROWS, [False] * COLS
for r in range(ROWS):
for c in range(COLS):
if matrix[r][c] == 0:
rows[r] = True
cols[c] = True
for r in range(ROWS):
for c in range(COLS):
if rows[r] or cols[c]:
matrix[r][c] = 0Where is the number of rows and is the number of columns.
We need to set an entire row and column to 0 if any cell in that row or column is 0.
The common two-array solution uses extra space to remember which rows/columns should be zeroed.
To optimize space, we can reuse the matrix itself as the "marker storage":
One complication:
matrix[0][0] sits at the intersection of the first row and first column, so it can't independently represent both.That's why we keep a boolean rowZero:
rowZero = true means the first row must be zeroed at the end.rowZero = false.(r, c):matrix[r][c] == 0:matrix[0][c] = 0r > 0, mark the row by setting matrix[r][0] = 0r == 0, set rowZero = true (first row needs to be zeroed)r from 1 to ROWS - 1:c from 1 to COLS - 1:matrix[0][c] == 0 or matrix[r][0] == 0, set matrix[r][c] = 0matrix[0][0] == 0, zero out the entire first columnrowZero is true, zero out the entire first rowclass Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
ROWS, COLS = len(matrix), len(matrix[0])
rowZero = False
for r in range(ROWS):
for c in range(COLS):
if matrix[r][c] == 0:
matrix[0][c] = 0
if r > 0:
matrix[r][0] = 0
else:
rowZero = True
for r in range(1, ROWS):
for c in range(1, COLS):
if matrix[0][c] == 0 or matrix[r][0] == 0:
matrix[r][c] = 0
if matrix[0][0] == 0:
for r in range(ROWS):
matrix[r][0] = 0
if rowZero:
for c in range(COLS):
matrix[0][c] = 0Where is the number of rows and is the number of columns.
Setting cells to zero while still scanning causes cascading updates where newly created zeros trigger more rows and columns to be zeroed. This produces incorrect results because the algorithm cannot distinguish between original zeros and zeros created during processing.
In the space-optimized approach, matrix[0][0] serves double duty for marking both the first row and first column. Using a single variable to track both leads to incorrect results. A separate boolean is needed to track whether the first row originally contained a zero.
When using the first row and column as markers, the order of applying updates matters. If you zero the first row or column too early, you lose the marker information needed to process the rest of the matrix. Always update the inner cells first, then handle the first row and column last.