Set Matrix Zeroes

需求:

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in-place.

Example 1:

Input: 
[
  [1,1,1],
  [1,0,1],
  [1,1,1]
]
Output: 
[
  [1,0,1],
  [0,0,0],
  [1,0,1]
]

分析:

1、思路一:空间复杂度O(m+n),其中m是行数,n是列数。

创建两个int数组,长度分别是m和n,存储对应的行和列是否需要置零,值是0表示该行或者该列不需要置零,是1表示需要将该行或该列置零。

2、思路二:空间复杂度O(m+n),其中m是行数,n是列数。

创建两个hash表,遍历二维数组,对于元素matrix[i][j]=0,将行号i和列号j分别存到两个hash表中,因为hash表可以保证元素的唯一性,所以可以保证行号和列号不重复,避免重复赋值。空间复杂度在于两个hash表,最多存储m个行号,n个列号,所以空间复杂度是O(m+n)。

3、思路三:空间复杂度O(1)
思路一和二中,都是需要额外的空间来存储需要置零的行号和列号,我们可以不需要这些额外空间,利用已有空间即可记录需要置零的行和列。
1)遍历第一行和第一列,如果有0,用两个boolean变量存储
2)遍历剩余的数字,假设某个值matrix[i][j]=0,那么行i和列j都要置零,我们可以将matrix[i][0]置零,表示i行需要置零,同时将matrix[0][j]置零,表示j列需要置零。这样,遍历结束之后,需要置零的行和列都可以通过第一行和第一列的数字表示出来,对于第一列,如果元素是0,那就将该行置零,对于第一行,如果元素是0,那么这一列置零。
3)遍历第一行和第一列如果是0,那么将该行或者该列(除了第一行和第一列)元素置零。最后处理第一行和第一列,看之前的两个boolean变量值,如果是true,那么将对应的行或列置0

代码:

class Solution {
    public void setZeroes(int[][] matrix) {
        //异常处理
        if(matrix == null || matrix.length == 0)
            return;
        
        /*
        思路一:
        空间复杂度O(m+n),其中m是行数,n是列数。
        创建两个int数组,长度分别是m和n,存储行和列是否需要置零,值是0表示该行或者该列不需要置零,是1表示需要将该行或该列置零
        */
        /*
        int[] row = new int[matrix.length];
        int[] col = new int[matrix[0].length];
        
        //遍历数组,如果值是0,修改数组row和col中元素的值为1,表示该行或者该列应该置为0
        for(int i = 0; i < matrix.length; i++){
            for(int j = 0; j < matrix[0].length; j++){
                if(matrix[i][j] == 0){
                    row[i] = 1;
                    col[j] = 1;
                }
            }
        }
        
        //将相应的行的元素置零
        for(int i = 0; i < row.length; i++){
            if(row[i] == 1){
                for(int j = 0; j < matrix[0].length; j++){
                    matrix[i][j] = 0;
                }
            }
        }
        
        //将相应的列的元素置零
        for(int i = 0; i < col.length; i++){
            if(col[i] == 1){
                for(int j = 0; j < matrix.length; j++){
                    matrix[j][i] = 0;
                }
            }
        }
        
        return;
        */
        
        /*
        思路二:
        空间复杂度O(m+n),其中m是行数,n是列数。
        创建两个hash表,遍历二维数组,对于元素matrix[i][j]=0,将行号i和列号j分别存到两个hash表中,因为hash表可以保证元素的唯一性,所以可以保证行号和列号不重复,避免重复赋值。空间复杂度在于两个hash表,最多存储m个行号,n个列号,所以空间复杂度是O(m+n)。
        */
        /*
        //创建两个hash表,一个存储0所在的行号,一个存储0所在的列号,然后将行和列对应的位置置0
        HashSet<Integer> row = new HashSet<Integer>();
        HashSet<Integer> col = new HashSet<Integer>();
        
        //遍历二维数组,如果是0,把其对应的行号和列号存到hash表
        for(int i = 0; i < matrix.length; i++){
            for(int j = 0; j < matrix[0].length; j++)
                if(matrix[i][j] == 0)
                {
                    row.add(i);
                    col.add(j);
                }
        }
        
        //把hash表中的对应行和列的元素都置为0
        //将对应的行都置为0
        for(Integer rows : row){
            for(int i = 0; i < matrix[0].length; i++)
                matrix[rows][i] = 0;
        }
        
        //将对应的列都置为0
        for(Integer cols : col){
            for(int i = 0; i < matrix.length; i++)
                matrix[i][cols] = 0;
        }
        
        return;
        */
        
        /*
        思路三:复杂度O(1),不需要额外的空间。
        思路一和二中,都是需要额外的空间来存储需要置零的行号和列号,我们可以不需要这些额外空间,利用已有空间即可记录需要置零的行和列。
        1)遍历第一行和第一列,如果有0,用两个boolean变量存储
        2)遍历剩余的数字,假设某个值matrix[i][j]=0,那么行i和列j都要置零,我们可以将matrix[i][0]置零,表示i行需要置零,同时将matrix[0][j]置零,表示j列需要置零。这样,遍历结束之后,需要置零的行和列都可以通过第一行和第一列的数字表示出来,对于第一列,如果元素是0,那就将该行置零,对于第一行,如果元素是0,那么这一列置零。
        3)遍历第一行和第一列如果是0,那么将该行或者该列(除了第一行和第一列)元素置零。最后处理第一行和第一列,看之前的两个boolean变量值,如果是true,那么将对应的行或列置0
        */
        boolean rowhas0 = false, colhas0 = false;
        
        //判断第一行是否有0
        for(int i = 0; i < matrix[0].length; i++)
        {
            if(matrix[0][i] == 0)
            {
                rowhas0 = true;
                break;
            }
        }
        //判断第一列是否有0
        for(int i = 0; i < matrix.length; i++){
            if(matrix[i][0] == 0){
                colhas0 = true;
                break;
            }
        }
        
        //从第二行第二列开始遍历
        for(int i = 1; i < matrix.length; i++){
            for(int j = 1; j < matrix[0].length; j++){
                if(matrix[i][j] == 0){
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }
        
        //遍历第一行,把相应的列置零
        for(int i = 1; i < matrix[0].length; i++){
            if(matrix[0][i] == 0){
                for(int j = 1; j < matrix.length; j++)
                    matrix[j][i] = 0;
            }
        }
        
        //遍历第一列,把相应的行置零
        for(int i = 1; i < matrix.length; i++){
            if(matrix[i][0] == 0){
                for(int j = 1; j < matrix[0].length; j++)
                    matrix[i][j] = 0;
            }
        }
        
        //单独处理第一行和第一列,看是否需要置零
        if(rowhas0){
            for(int i = 0; i < matrix[0].length; i++)
                matrix[0][i] = 0;
        }
        
        if(colhas0){
            for(int i = 0; i < matrix.length; i++)
                matrix[i][0] = 0;
        }
        
        return;
    }
}

点赞