给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
思路
想法
第二种方法不高效的地方在于我们会重复对同一行或者一列赋零。我们可以推迟对行和列赋零的操作。
我们可以用每行和每列的第一个元素作为标记,这个标记用来表示这一行或者这一列是否需要赋零。这意味着对于每个节点不需要访问 M+NM+N 个格子而是只需要对标记点的两个格子赋值。
if cell[i][j] == 0 { cell[i][0] = 0 cell[0][j] = 0 }
这些标签用于之后对矩阵的更新,如果某行的第一个元素为零就将整行置零,如果某列的第一个元素为零就将整列置零。
算法
遍历整个矩阵,如果 cell[i][j] == 0 就将第 i 行和第 j 列的第一个元素标记。
第一行和第一列的标记是相同的,都是 cell[0][0],所以需要一个额外的变量告知第一列是否被标记,同时用 cell[0][0] 继续表示第一行的标记。
然后,从第二行第二列的元素开始遍历,如果第 r 行或者第 c 列被标记了,那么就将 cell[r][c] 设为 0。这里第一行和第一列的作用就相当于方法一中的 row_set 和 column_set 。
然后我们检查是否 cell[0][0] == 0 ,如果是则赋值第一行的元素为零。
然后检查第一列是否被标记,如果是则赋值第一列的元素为零。
作者:LeetCode
链接:https://leetcode-cn.com/problems/two-sum/solution/ju-zhen-zhi-ling-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
代码
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
int flag = 1;
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) flag = 0;
}
for (int i = 0; i < n; i++) {
if (matrix[0][i] == 0) matrix[0][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;
}
}
}
for (int i = 1; i < n; i++) {
if (matrix[0][i] == 0) for (int j = 0; j < m; j++) matrix[j][i] = 0;
}
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) for (int j = 0; j < n; j++) matrix[i][j] = 0;
}
if (flag == 0) for (int j = 0; j < m; j++) matrix[j][0] = 0;
}
};
写的很丑,尽力了。
总结
第二种方法不高效的地方在于我们会重复对同一行或者一列赋零。我们可以推迟对行和列赋零的操作。
我们可以用每行和每列的第一个元素作为标记,这个标记用来表示这一行或者这一列是否需要赋零。
推迟修改,进行标记,通过添加额外的信息来解决问题。