[LintCode/LeetCode/CC] Set Matrix Zeroes

411 查看

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

把矩阵所有零点的行和列都置零,要求不要额外的空间。基本的思路是把这些零点坐标的行和列都标记下来,只不过把标记存在首行和首列。对于首行和首列的零点,进行额外的标记即可。所以,算法的步骤为:
首行、首列标记:分别标记首行和首列是否有零点
子矩阵标记:遍历除首行和首列之外的整个矩阵,将所有零点的坐标分别标记在首行和首列
子矩阵置零:遍历除首行和首列的整个矩阵的所有点,若某点映射在首行或首列的同列点或同行点为零点,便置该点为零点
首行、首列置零:最后分别处理首行、首列,若标记有零点,则首行、首列全部置零。
这道题我自己做了四遍,下面几个问题需要格外注意:

  1. 标记首行和首列时,从0到m遍历matrix[i][0]时,若有零点,则首列标记为true;从0到n遍历matrix[0][j],若有零点,则首行标记为true。

  2. 必须先标记和置零子矩阵,即行和列的循环都从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;
        }
    }
}