73. Set Matrix Zeroes
Problem Description
Given a 2D matrix of integers, the challenge is to modify the matrix such that if any cell contains the value 0
, then all cells in the same row and column as that 0
are set to 0
. The crucial requirement is that this transformation must be done 'in place,' which means you cannot use any additional memory to store large temporary data structures like a copy of the original matrix. The goal is to achieve the required transformation efficiently with respect to space.
Intuition
To solve this problem we need to track the rows and columns that must be set to 0
without using extra space for another matrix. We can use two boolean variables (i0
and j0
) to keep track of whether the first row and the first column should be zeroed as they will serve as markers.
Here is an intuition for the solution approach:
-
If we find a
0
in any cell of the matrix, the row and column of that cell must be zeroed out. However, if we immediately reset all cells in the same row and column to0
, information about other0
s in those rows and columns could be lost. -
To work around this, we can use the first cell of each row and column as a flag that indicates whether that entire row or column should be set to
0
. -
First, we check if the first row and first column should be zeroed by looking for any
0
s and store this information ini0
for the first row, andj0
for the first column. -
We iterate over the rest of the matrix (to avoid overriding
i0
andj0
flags) and if we find a0
, we set the first cell of that row and column to0
. These markers will be used later to update the rows and columns. -
After marking, we iterate over the matrix again, ignoring the first row and column, and update cells to
0
if their row or column marker is0
. -
Finally, we use
i0
andj0
to set the first row and column to0
if needed.
This approach allows us to keep track of which rows and columns need to be zeroed without using additional space, hence giving us an in-place solution.
Solution Approach
The solution involves a few logical steps to minimize space complexity while ensuring the entire row and column are set to 0
for each 0
in the matrix. Here's a step-by-step breakdown:
-
Initialization: We initialize two boolean variables
i0
andj0
. We usei0
to check if the first row needs to be set to0
by iterating through the first row. Similarly,j0
is used to check if the first column needs to be set to0
by iterating down the first column. -
Marking Rows and Columns: To preserve the information of where
0
s are in the matrix without using extra space, we use the first row and column of the matrix itself. As we iterate through the matrix starting from element at (1,1), if a0
is encountered at position(i,j)
, we mark the first element of rowi
(at position(i,0)
) and the first element of columnj
(at position(0,j)
) to0
.This way, we're using the matrix itself to keep track of rows and columns that will eventually be zeroed out. This clever trick avoids the need for additional data structures for marking purposes.
-
Zeroing Rows and Columns: Having marked the rows and columns that need to be updated, we now iterate again through the matrix starting from element at (1,1) to
m-1 x n-1
. For any cell(i,j)
, we check if the first element of rowi
or the first element of columnj
is0
. If either is0
, this implies the current cell should also be0
, and we update it accordingly. -
Finalizing the First Row and Column: We check
i0
andj0
from the first step. Ifi0
is true, we zero out the first row. Similarly, ifj0
is true, we zero out the first column.
This in-place algorithm cleverly exploits the matrix's own first row and column to store the state needed to carry out the required transformation. This results in an O(1)
space complexity as no additional storage proportional to the size of the matrix is needed, and the time complexity remains O(m x n)
since we need to potentially look at all elements in the m x n
matrix twice.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's consider a small 3x3 example matrix to illustrate the solution approach:
Matrix before: [ [1, 2, 3], [4, 0, 6], [7, 8, 9] ]
-
Initialization:
i0
andj0
are initially set tofalse
. We inspect the first row and first column to check for any0
s:- First row has no
0
, thusi0
remainsfalse
. - First column also has no
0
, soj0
remainsfalse
.
- First row has no
-
Marking Rows and Columns: We start inspecting from (1,1):
- No
0
at (1,1) — we move on. - We find a
0
at (1,3), so we mark the first element of row 1 (at position (1,0)) and the first element of column 3 (at position (0,3)) to0
.
Now the matrix looks like this with markers set:
[ [1, 2, 0], // Column 3 marked [0, 0, 6], // Row 1 marked and the encountered 0 [7, 8, 9] ]
- No
-
Zeroing Rows and Columns: With our markers set, we iterate through the matrix starting at (1,1) again and update according to markers:
- Cell (1,1) stays
1
since neither the first element of row 1 nor column 1 is0
. - Cell (1,2) becomes
0
because the first element of column 2 (position (0,2)) is0
. - Continue through the matrix, checking the respective row or column start for a
0
marker.
Updated matrix now looks like this:
[ [1, 0, 0], // Column 3 zeroed out [0, 0, 0], // Row 1 zeroed out [7, 0, 9] ] // Column 2 zeroed out because of the marker at (0,2)
- Cell (1,1) stays
-
Finalizing the First Row and Column: Since
i0
andj0
are bothfalse
, we know the first row and column can remain unchanged.
The final matrix after performing the in-place transformation looks like:
[ [1, 0, 0], [0, 0, 0], [7, 0, 9] ]
This demonstrates how the matrix is correctly transformed according to the problem's rules without using any additional space, as all the zeroing information is stored within the original matrix itself.
Solution Implementation
1class Solution:
2 def set_zeroes(self, matrix: List[List[int]]) -> None:
3 # Get the dimensions of the matrix
4 nrows, ncols = len(matrix), len(matrix[0])
5
6 # Determine if the first row has any zeroes
7 first_row_has_zero = any(value == 0 for value in matrix[0])
8 # Determine if the first column has any zeroes
9 first_col_has_zero = any(matrix[row][0] == 0 for row in range(nrows))
10
11 # Use the first row and column as flags for zeroes
12 # Start from 1 to avoid overwriting the first row and column flags
13 for row in range(1, nrows):
14 for col in range(1, ncols):
15 # If an element is zero, mark its row and column in the first row and column
16 if matrix[row][col] == 0:
17 matrix[row][0] = matrix[0][col] = 0
18
19 # Set matrix elements to zero based on flags in the first row and column,
20 # ignoring the first row and column themselves
21 for row in range(1, nrows):
22 for col in range(1, ncols):
23 if matrix[row][0] == 0 or matrix[0][col] == 0:
24 matrix[row][col] = 0
25
26 # If the first row had zeroes, set all elements in the first row to zero
27 if first_row_has_zero:
28 for col in range(ncols):
29 matrix[0][col] = 0
30
31 # If the first column had zeroes, set all elements in the first column to zero
32 if first_col_has_zero:
33 for row in range(nrows):
34 matrix[row][0] = 0
35
1class Solution {
2 public void setZeroes(int[][] matrix) {
3 int rowCount = matrix.length; // number of rows in the matrix
4 int colCount = matrix[0].length; // number of columns in the matrix
5 boolean firstRowHasZero = false; // flag to check if the first row contains a zero
6 boolean firstColHasZero = false; // flag to check if the first column contains a zero
7
8 // Check if the first row has any zeros
9 for (int col = 0; col < colCount; ++col) {
10 if (matrix[0][col] == 0) {
11 firstRowHasZero = true;
12 break;
13 }
14 }
15
16 // Check if the first column has any zeros
17 for (int row = 0; row < rowCount; ++row) {
18 if (matrix[row][0] == 0) {
19 firstColHasZero = true;
20 break;
21 }
22 }
23
24 // Use the first row and column as markers.
25 // Set matrix[i][0] and matrix[0][j] to 0 if matrix[i][j] is 0
26 for (int row = 1; row < rowCount; ++row) {
27 for (int col = 1; col < colCount; ++col) {
28 if (matrix[row][col] == 0) {
29 matrix[row][0] = 0;
30 matrix[0][col] = 0;
31 }
32 }
33 }
34
35 // Iterate over the matrix again using the first row and column as reference,
36 // and set the elements to 0 accordingly.
37 for (int row = 1; row < rowCount; ++row) {
38 for (int col = 1; col < colCount; ++col) {
39 if (matrix[row][0] == 0 || matrix[0][col] == 0) {
40 matrix[row][col] = 0;
41 }
42 }
43 }
44
45 // Nullify the first row if needed
46 if (firstRowHasZero) {
47 for (int col = 0; col < colCount; ++col) {
48 matrix[0][col] = 0;
49 }
50 }
51
52 // Nullify the first column if needed
53 if (firstColHasZero) {
54 for (int row = 0; row < rowCount; ++row) {
55 matrix[row][0] = 0;
56 }
57 }
58 }
59}
60
1class Solution {
2public:
3 void setZeroes(vector<vector<int>>& matrix) {
4 int rowCount = matrix.size(), colCount = matrix[0].size();
5 bool firstRowHasZero = false, firstColHasZero = false;
6
7 // Check if the first row has a zero
8 for (int col = 0; col < colCount; ++col) {
9 if (matrix[0][col] == 0) {
10 firstRowHasZero = true;
11 break;
12 }
13 }
14
15 // Check if the first column has a zero
16 for (int row = 0; row < rowCount; ++row) {
17 if (matrix[row][0] == 0) {
18 firstColHasZero = true;
19 break;
20 }
21 }
22
23 // Use first row and column as markers, set matrix[i][0] and matrix[0][j] to 0 if matrix[i][j] is 0
24 for (int row = 1; row < rowCount; ++row) {
25 for (int col = 1; col < colCount; ++col) {
26 if (matrix[row][col] == 0) {
27 matrix[row][0] = 0;
28 matrix[0][col] = 0;
29 }
30 }
31 }
32
33 // Iterate over the matrix, set elements to 0 if their row or column marker is 0
34 for (int row = 1; row < rowCount; ++row) {
35 for (int col = 1; col < colCount; ++col) {
36 if (matrix[row][0] == 0 || matrix[0][col] == 0) {
37 matrix[row][col] = 0;
38 }
39 }
40 }
41
42 // If the first row had zero, set all elements in the first row to 0
43 if (firstRowHasZero) {
44 for (int col = 0; col < colCount; ++col) {
45 matrix[0][col] = 0;
46 }
47 }
48
49 // If the first column had zero, set all elements in the first column to 0
50 if (firstColHasZero) {
51 for (int row = 0; row < rowCount; ++row) {
52 matrix[row][0] = 0;
53 }
54 }
55 }
56};
57
1/**
2 * Modifies a given matrix by setting entire rows and columns to zero if an element in them is zero.
3 * Operates in-place.
4 * @param {number[][]} matrix - A 2D array of numbers to be modified.
5 */
6function setZeroes(matrix: number[][]): void {
7 // Dimensions of the matrix
8 const rowCount = matrix.length;
9 const colCount = matrix[0].length;
10
11 // Flags indicating if the first row/column contains a zero
12 const isFirstRowZero = matrix[0].includes(0);
13 const isFirstColZero = matrix.some(row => row[0] === 0);
14
15 // Use first row/column as markers for zero rows/columns.
16 for (let row = 1; row < rowCount; ++row) {
17 for (let col = 1; col < colCount; ++col) {
18 if (matrix[row][col] === 0) {
19 // Mark the respective first row and column cell
20 matrix[row][0] = 0;
21 matrix[0][col] = 0;
22 }
23 }
24 }
25
26 // Set matrix cells to zero based on the marks
27 for (let row = 1; row < rowCount; ++row) {
28 for (let col = 1; col < colCount; ++col) {
29 if (matrix[row][0] === 0 || matrix[0][col] === 0) {
30 matrix[row][col] = 0;
31 }
32 }
33 }
34
35 // If the first row needs to be set to zero
36 if (isFirstRowZero) {
37 for (let col = 0; col < colCount; col++) {
38 matrix[0][col] = 0;
39 }
40 }
41
42 // If the first column needs to be set to zero
43 if (isFirstColZero) {
44 for (let row = 0; row < rowCount; row++) {
45 matrix[row][0] = 0;
46 }
47 }
48}
49
Time and Space Complexity
The given code has a time complexity of O(m * n)
where m
is the number of rows and n
is the number of columns in the given matrix. This is because the algorithm visits each cell twice, once to mark the rows and columns that should be zeroed and once to actually set the zeros.
For space complexity, the algorithm is O(1)
as it uses constant extra space regardless of the size of the matrix. This is achieved by using the first row and first column of the matrix to store flags indicating whether a row or column should be set to zero.
Learn more about how to find time and space complexity quickly using problem constraints.
Consider the classic dynamic programming of fibonacci numbers, what is the recurrence relation?
Recommended Readings
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!