题目:
代码(首刷自解 2024年3月3日):
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
unordered_set<int> row;
unordered_set<int> column;
//找出0的位置并记录下来
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (matrix[i][j] == 0) {
row.insert(i);
column.insert(j);
}
}
}
//原数组置0
for (const auto it : row) {
for (int i = 0; i < n; ++i) matrix[it][i] = 0;
}
for (const auto it : column) {
for (int i = 0; i < m; ++i) matrix[i][it] = 0;
}
}
};
代码(二刷半自解 2024年3月28日 原地算法)
要先用两个参数对第一行和第一列是否有0做标记,然后再从第二行第二列开始遍历,遇到0就给其对应的第1行第1列置为0,然后根据第一行第一列的0,将非第一行非第一列的数字置0,最后根据两个参数是否为true对第一行/第一列的元素置0。
其实我认为,使用了row_flag也算是用了额外空间,虽然是常数级。这题要真正地实现不用任何额外空间的做法我认为应该是位运算,比如将int的二进制最高位设为0表示该位置要置为0,否则不置0,然后第二次计算的时候直接位运算。
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
bool row_flag = false, col_flag = false;
//记录第一行第一列是否有0
for (int i = 0; i < m; ++i) {
if (matrix[i][0] == 0){ col_flag = true; break;}
}
for (int j = 0; j < n; ++j) {
if (matrix[0][j] == 0){ row_flag = true; break;}
}
// 遍历数组,遇到0就将其第一行,第一列置为0
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
if (matrix[i][j] == 0) {
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
//根据第一行第一列是否为0将除了第一行第一列的元素置0
for (int i = 1; i < m; ++i) {
if (matrix[i][0] == 0) {
for (int j = 1; j < n; ++j)
matrix[i][j] = 0;
}
}
for (int j = 1; j < n; ++j) {
if (matrix[0][j] == 0) {
for (int i = 1; i < m; ++i)
matrix[i][j] = 0;
}
}
//根据bool变量设置第一行第一列是否为0
if (row_flag)
for (int i = 0; i < n; ++i) matrix[0][i] = 0;
if (col_flag)
for (int i = 0; i < m; ++i) matrix[i][0] = 0;
}
};