給定一個 m x n 的整數矩陣,若某元素為 0,則將其所在的整行與整列所有元素設為 0。要求 原地修改,空間複雜度最優為 O(1)。
第一遍掃描記錄哪些行、哪些列需要置零;第二遍根據記錄執行置零操作。若直接在矩陣上標記會干擾後續判斷,故需額外存儲標記信息。
row[i] 表示第 i 行含 0col[j] 表示第 j 列含 0掃描矩陣建立標記,再遍歷執行置零。時間 O(mn),空間 O(m+n),實現簡單直觀。
firstRowZero, firstColZero。(i,j) (i>0, j>0),若為 0,則將 matrix[i][0]=0 和 matrix[0][j]=0 作為標記。firstRowZero, firstColZero 決定是否將首行、首列置零。此法達到 O(1) 額外空間,是面試期望的最優解。
void setZeroes(vector<vector<int>> &matrix) {
if (matrix.empty()) return;
int rows = matrix.size(), cols = matrix[0].size();
vector<bool> row(rows, false), col(cols, false);
// 第一遍:記錄含 0 的行列
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
if (matrix[i][j] == 0)
row[i] = col[j] = true;
// 第二遍:執行置零
for (int i = 0; i < rows; ++i)
if (row[i])
fill(matrix[i].begin(), matrix[i].end(), 0);
for (int j = 0; j < cols; ++j)
if (col[j])
for (int i = 0; i < rows; ++i)
matrix[i][j] = 0;
}
matrix.empty() 避免訪問越界。false,遇 0 置 true,避免重複掃描。| 方法 | 時間 | 空間 | 備註 |
|---|---|---|---|
| 布爾數組 | O(mn) | O(m+n) | 易理解、易實現 |
| 首行首列標記 | O(mn) | O(1) | 最優空間,邊界處理稍繁瑣 |
若矩陣極大且稀疏,可考慮用 unordered_set 記錄非零行列索引,進一步減少第二遍掃描範圍。但對於常規題目約束,上述兩種方法已足夠。