Problem
Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
Example
Given a matrix
[
[1,2],
[0,3]
],
return
[
[0,2],
[0,0]
]
Challenge
Did you use extra space?
A straight forward solution using O(mn) space is probably a bad idea.
A simple improvement uses O(m + n) space, but still not the best solution.
Could you devise a constant space solution?
Note
把矩阵所有零点的行和列都置零,要求不要额外的空间。基本的思路是把这些零点坐标的行和列都标记下来,只不过把标记存在首行和首列。对于首行和首列的零点,进行额外的标记即可。所以,算法的步骤为:
首行、首列标记:分别标记首行和首列是否有零点;
子矩阵标记:遍历除首行和首列之外的整个矩阵,将所有零点的坐标分别标记在首行和首列;
子矩阵置零:遍历除首行和首列的整个矩阵的所有点,若某点映射在首行或首列的同列点或同行点为零点,便置该点为零点;
首行、首列置零:最后分别处理首行、首列,若标记有零点,则首行、首列全部置零。
这道题我自己做了四遍,下面几个问题需要格外注意:
标记首行和首列时,从0到m遍历
matrix[i][0]
时,若有零点,则首列标记为true;从0到n遍历matrix[0][j]
,若有零点,则首行标记为true。必须先标记和置零子矩阵,即行和列的循环都从1开始,否则会影响最后对首行和首列的置零。
Solution
public class Solution {
public void setZeroes(int[][] matrix) {
boolean row = false, col = false;
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return;
int m = matrix.length, n = matrix[0].length;
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) col = true;
}
for (int j = 0; j < n; j++) {
if (matrix[0][j] == 0) row = true;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][j] == 0) {
matrix[i][0] = matrix[0][j] = 0;
}
}
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
for (int i = 0; i < m && col; i++) {
matrix[i][0] = 0;
}
for (int j = 0; j < n && row; j++) {
matrix[0][j] = 0;
}
}
}