描述
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
原题链接
思路
方法1:可以考虑设置两个数组,存储即将要归0的行数与列数;扫描一遍矩阵,如果遇到0,则将其行数、列数放入数组中;然后遍历两个数组,将相应行数和列数归零,这个方法思路简单,但需要一定的空间复杂度来存储行数和列数;
方法2(省空间):我们可以考虑将需要归零的行和列标识出来,并且标识不需要另外的数组的存储,直接在矩阵中标记即可。
如何实现这种标记?即若出现0,则将其所在行的第一列的数归为0,将其所在列的第一行的数归为0,这样便可以实现标记;
但这样的标记会出现几个问题:
① 第一行或者第一列产生的标记都会放在最左上角的元素上,而对于左上角元素如何处理?(行的清零与列的清零都标识在该元素上,无法确定是行清零还是列清零)我们可以选择将第一行与第一列单独拿出来判断,一开始就从第二行第二列开始;
② 非第一列第一行的数产生的标记,会把原第一行或者第一列为0的数覆盖,这会造成原本的0所要归0的行或列被遗漏;解决办法是设置一个布尔变量,一开始优先把第一行与第一列扫描,若第一行(列)扫描到零,用该变量标识该行(列)需要置零;这样问题便解决了;
详细代码
class Solution {
public void setZeroes(int[][] matrix) {
Boolean isCol = false;
Boolean isRow = false;
int R = matrix.length;
int C = matrix[0].length;
for(int i=0;i<R;i++){ //标记第一列,如果第一列出现0,标记
if(matrix[i][0]==0){
isCol = true;
}
}
for(int i=0;i<C;i++){ //标记第一行
if(matrix[0][i]==0){
isRow = true;
}
}
for (int i = 1; i < R; i++) { //标记非首行首列的元素
for (int j = 1; j < C; j++) {
if (matrix[i][j] == 0) {
matrix[0][j] = 0;
matrix[i][0] = 0;
}
}
}
for (int i = 1; i < R; i++) { //根据标记将非首行首列元素清零
for (int j = 1; j < C; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
if (isRow) { //根据首行标记来清零首行
for (int j = 0; j < C; j++) {
matrix[0][j] = 0;
}
}
if (isCol) { //根据首列标记来清零首列
for (int i = 0; i < R; i++) {
matrix[i][0] = 0;
}
}
}
}