Set Matrix Zeroes: Optimal C++ Algorithm Guide
Set Matrix Zeroes is a classic algorithmic challenge that tests your ability to optimize both time and space complexity. The core problem requires you to identify all elements with a zero value within an $m \times n$ matrix and subsequently set their entire corresponding row and column to zero. While a naive approach might use extra memory to store the coordinates of these zeros, the true test of expertise lies in achieving an in-place solution with $O(1)$ space complexity.
In this comprehensive guide, we will explore the optimal C++ implementation for the Set Matrix Zeroes problem, breaking down the logic behind using the matrix's own first row and column as a dynamic programming tracking table.
Optimal C++ Solution
The following C++ implementation achieves $O(m \times n)$ time complexity and an optimal $O(1)$ space complexity by leveraging the first row and first column as marker states.
class Solution {
public:
void setMatrixZeroes(vector<vector<int>>& mat) {
int n = mat.size();
int m = mat[0].size();
bool firstRowHasZero = false;
bool firstColHasZero = false;
// Check if the first row has any zero
for (int j = 0; j < m; j++) {
if (mat[0][j] == 0) {
firstRowHasZero = true;
break;
}
}
// Check if the first column has any zero
for (int i = 0; i < n; i++) {
if (mat[i][0] == 0) {
firstColHasZero = true;
break;
}
}
// Use the first row and column to mark zeros
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
if (mat[i][j] == 0) {
mat[i][0] = 0;
mat[0][j] = 0;
}
}
}
// Update the matrix based on the markers
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
if (mat[i][0] == 0 || mat[0][j] == 0) {
mat[i][j] = 0;
}
}
}
// Update the first row if needed
if (firstRowHasZero) {
for (int j = 0; j < m; j++) {
mat[0][j] = 0;
}
}
// Update the first column if needed
if (firstColHasZero) {
for (int i = 0; i < n; i++) {
mat[i][0] = 0;
}
}
}
};
How the In-Place Algorithm Works
The brilliance of this approach lies in using the first row and column as a dynamic programming table to mark which rows and columns need to be zeroed out. This avoids the need for external data structures, satisfying the strict $O(1)$ space requirement.
1. Initial Scanning for the First Row and Column
Before modifying the matrix for tracking, we must first determine if the first row or first column natively contains any zeros. We store these boolean states in firstRowHasZero and firstColHasZero. This step is crucial because we will overwrite these boundaries during the next phase.
2. Marking Rows and Columns
We iterate through the remainder of the matrix (from index 1 to $n-1$ and $1$ to $m-1$). Whenever we encounter a zero at mat[i][j], we project this information to the edges by setting mat[i][0] = 0 and mat[0][j] = 0. This effectively flags row $i$ and column $j$ for future modification.
3. Applying the Zeroes
With our markers established, we perform a second pass through the inner matrix. For every cell mat[i][j], we check its corresponding markers at mat[i][0] and mat[0][j]. If either marker is zero, we update the cell to zero.
4. Restoring the Boundaries
Finally, we revisit the boolean flags evaluated in step one. If the first row originally contained a zero, we zero out the entire first row. We apply the same logic to the first column. This ensures the matrix boundaries accurately reflect their initial state requirements.
Frequently Asked Questions (FAQ)
What is the time complexity of the Set Matrix Zeroes algorithm?
The time complexity is $O(m \times n)$, where $m$ is the number of rows and $n$ is the number of columns. We traverse the entire matrix a constant number of times, making it computationally optimal.
Why is an O(1) space complexity solution preferred?
An $O(1)$ auxiliary space complexity solution is preferred because it modifies the input matrix in-place without requiring additional memory proportional to the matrix size. This is a common constraint in technical interviews to test algorithmic efficiency.
Can this algorithm handle matrices with negative numbers?
Yes, this algorithm correctly handles matrices containing any integer values, including negative numbers. It specifically targets elements that are exactly equal to zero, leaving other values unmodified unless they fall within a zeroed row or column.