class Solution {
public:
void setZeroes(vector<vector<int> > &matrix) {
int h = matrix.size();
if(h == 0){
return;
}
int w = matrix[0].size();
if(w == 0){
return;
}
for(int i = 0; i < h; ++i){
for(int j = 0; j < w; ++j){
if(matrix[i][j] == 0){
for(int k = 0; k < w; ++k){
matrix[i][k] = 0;
}
break;
}
}
}
for(int i = 0; i < w; ++i){
for(int j = 0; j < h; ++j){
if(matrix[i][j] == 0){
for(int k = 0; k < h; ++k){
matrix[k][i] = 0;
}
}
break;
}
}
}
};
上述解法错误,因为第一个二重循环将所有含有0的行置为全0,而第二个二重循环将所有列清零的依据是,该列中至少有一个零元素,而实际上,引起这一列清零的不一定是原矩阵中的零,而是第一个二重循环置的零;
同理在矩阵中每遇到一个元素就更新其行or列也会遇到相似的问题
下面是一个跑的很慢但是Accepted的solution:
class Solution {
public:
void setZeroes(vector<vector<int> > &matrix) {
bool firstColumnZero = false, firstRowZero = false;
int h = matrix.size();
if(h == 0){
return;
}
int w = matrix[0].size();
if(w == 0){
return;
}
for(int i = 0; i < w; ++i){
if(matrix[0][i] == 0){
firstRowZero = true;
break;
}
}
for(int i = 0; i < h; ++i){
if(matrix[i][0] == 0){
firstColumnZero = true;
break;
}
}
//didn't modify any of the elements in matrix
for(int i = 1; i < h; ++i){
for(int j = 1; j < w; ++j){
if(matrix[i][j] == 0){
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
for(int i = 1; i < w; ++i){
if(matrix[0][i] == 0){
//column i clear to zero
for(int k = 0; k < h; ++k){
matrix[k][i] = 0;
}
}
}
for(int i = 1; i < h; ++i){
//clear row i to zero
if(matrix[i][0] == 0){
for(int k = 0; k < w; ++k){
matrix[i][k] = 0;
}
}
}
if(firstRowZero){
for(int i = 0; i < w; ++i){
matrix[0][i] = 0;
}
}
if(firstColumnZero){
for(int i = 0; i < h; ++i){
matrix[i][0] = 0;
}
}
}
};
思路就是:
由于每一行or列是否被清零只与该行or列的元素有关而与别的元素无关
1. 预处理,看第一行是否有0元素,第一列是否有零元素(并用两个bool变量标记)
2. 把matrix[i][j] (i != 1 && j != 1)的为0的信息存在第一行或者第一列对应的位置
3. 用记录在第一行和第一列里的信息更新除第一行和第一列以外的元素
4. 根据两个bool变量更新第一行和第一列的元素
一开始写出了bug,就是代码最后两个if判断之前,修改了第一行和第一列用于标记状态的元素,从而使得只要matrix[0][0]为0,那么接着column 0被清零,然后每个row就都被清零了=。-
(总结起来就是对矩阵的清零操作影响了用于标记的行和列,接着使得这个清零因为矩阵的修改而传递(这是与题意相违背的))