题目描述
给定一个 m x n
的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
方法一:O(m + n)空间复杂度
开辟两个数组row[m]和col[n],分别记录下应该被置零的行号与列号,空间复杂度O(m + n)
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector<int>row(m,0);
vector<int>col(n,0);
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(!matrix[i][j]){
row[i] = 1;
col[j] = 1;
}
}
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(row[i]||col[j]) matrix[i][j] = 0;
}
}
}
};
方法二:O(1)空间复杂度
使用矩阵的第一行和第一列来保存方法一中的两个数组,这样就无需开辟额外的数组空间了。但需要用两个变量row0,col0来分别记录第一行是否有零出现,以及第二行是否有零出现。
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int row0 = 0, col0 = 0;
for(int i = 0; i < n; i++){
if(!matrix[0][i]) row0 = 1;
}
for(int i = 0; i < m; i++){
if(!matrix[i][0]) col0 = 1;
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
if(!matrix[i][j]){
matrix[0][j] = 0;
matrix[i][0] = 0;
}
}
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
if(!matrix[0][j]||!matrix[i][0]) matrix[i][j] = 0;
}
}
if(row0){
for(int i = 0; i < n; i++){
matrix[0][i] = 0;
}
}
if(col0){
for(int i = 0;i < m;i++){
matrix[i][0] = 0;
}
}
}
};
注意:其中第一行原本的零元素和第一列原本的零元素的处理是一个细节之处,以图中示例为例,第一行第四列为零,输出矩阵中第四列应该全为零。但在对矩阵的处理中,若观察完第一行第一列是否有零元素并记录在变量里之后,直接忽略第一行第一列,从第二行第二列开始观测并记录零元素是不可行的,因为如例所示的第一行第四列这个零元素就会被忽略掉。处理方式也非常简单,只要把标记零元素的标记值设为0即可,这样,如图所示这个零元素就会被自然地视作本列有零存在。
方法三:O(1)空间复杂度
这个方法同样是O(1)的空间复杂度,与方法二不同的是,方法三仅仅用了一个额外的变量。
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int col0 = 0;
for(int i = 0; i < m; i++){
if(!matrix[i][0]) col0 = 1;
for(int j = 1; j < n; j++){
if(!matrix[i][j]){
matrix[0][j] = 0;
matrix[i][0] = 0;
}
}
}
for(int i = m - 1; i >= 0; i--){
for(int j = 1; j < n; j++){
if(!matrix[0][j]||!matrix[i][0]) matrix[i][j] = 0;
}
}
if(col0){
for(int i = 0;i < m;i++){
matrix[i][0] = 0;
}
}
}
};
注意在写代码时,合并可以合并的循环以优化运行时间。