Set Matrix Zeroes

https://leetcode.com/problems/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.

click to show follow up.

Follow up:

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?

解题思路:

这道题看似简单,不知道要考什么。细细思考后,难度主要在于两点。

第一,不能遇到0就立刻将该行该列的所有元素都置为0,因为原来数组中就有0,该行该列可能本来就有0。这样无法判断到底是本来就是0,还是后来置为0的。

第二,如何用常数的空间来做。我们可以用一个set记录原来就是0的行号和列号,但需要m+n的空间。

下面先实现m+n的。

public class Solution {

    public void setZeroes(int[][] matrix) {

        Set<Integer> rowSet = new HashSet<Integer>();

        Set<Integer> columnSet = new HashSet<Integer>();

        

        for(int i = 0; i < matrix.length; i++){

            for(int j = 0; j < matrix[0].length; j++){

                if(matrix[i][j] == 0){

                    columnSet.add(j);

                    rowSet.add(i);

                }

            }

        }

        for(int i = 0; i < matrix.length; i++){

            for(int j = 0; j < matrix[0].length; j++){

                if(columnSet.contains(j)){

                    for(int k = 0; k < matrix.length; k++){

                        matrix[k][j] = 0;

                    }

                }

                if(rowSet.contains(i)){

                    for(int k = 0; k < matrix[0].length; k++){

                        matrix[i][k] = 0;

                    }

                }

            }

        }

    }

}

下面思考如何在常数空间内实现,百思不得其解,考虑人脑是如何做的。

Set Matrix Zeroes

遇到0就用线将他们连起来,而不能直接置为0,不然无法区分是不是原来就是0。然后再将所有的线置为0。这个过程不用额外空间,但是需要将元素临时置为一个不是integer的符号,以免与原来的元素冲突,这在所有元素都是integer的数组里做不到。

只能看看别人是怎么做的。思路如下。

借用每列的第一行和每行的第一列来存储当前列和当前行是不是有0,如果有0,就把当前行的第一列和当前列的第一行置为0,反正本来这里最后一定是0。

于是问题来了,最后处理第一行和第一列的标志位时,如何知道这里是作为标志的0,还是原来就为0?比如,如果原来matrx[1][0]就是0,那么这时第一列就要全部置为0,但如果matrx[1][0]是作为标志位的0,第一列是不能被全部置为0的,否则导致的结果是最后matrix所有元素都是0了。列的标志位(即第一行)也是同样的道理。

这里遇到的问题和上面的问题一样,就是如何区分标志位和原来的值。我们这里用另一个思路来解决。

最后借助标志位赋值时,只将从第二行和第二列开始的元素置为0。第一行和第一列是否置为0,不用标志位来看,借助另外两个变量firstColumnHasZero和firstRowHasZero,这两个变量在前面遍历matrix的时候另外存储。

public class Solution {

    public void setZeroes(int[][] matrix) {

        boolean firstColumnHasZero = false;

        boolean firstRowHasZero = false;

        

        for(int i = 0; i < matrix.length; i++){

            for(int j = 0; j < matrix[0].length; j++){

                if(matrix[i][j] == 0){

                    if(j == 0){

                        firstColumnHasZero = true;

                    }else{

                        matrix[0][j] = 0;

                        matrix[i][0] = 0;

                    }

                    if(i == 0){

                        firstRowHasZero = true;

                    }else{

                        matrix[0][j] = 0;

                        matrix[i][0] = 0;

                    }

                }

            }

        }

        //处理列

        for(int i = 1; i < matrix[0].length; i++){

            if(matrix[0][i] == 0){

                for(int k = 0; k < matrix.length; k++){

                    matrix[k][i] = 0;

                }

            }

        }

        

        //处理行

        for(int i = 1; i < matrix.length; i++){

            if(matrix[i][0] == 0){

                for(int k = 0; k < matrix[0].length; k++){

                    matrix[i][k] = 0;

                }

            }

        }

        if(firstRowHasZero){

            for(int k = 0; k < matrix[0].length; k++){

                matrix[0][k] = 0;

            }

        }

        if(firstColumnHasZero){

            for(int k = 0; k < matrix.length; k++){

                matrix[k][0] = 0;

            }

        }

    }

}

这道题要考的是,尽可能的缩减程序所需的空间。不过我感觉实用性不大,因为思路还是比较复杂的。但是有一点,就是知道思路后如何写出bug free的code。因为这段代码中循环很多,相应的边界值也很关键。能写出,或者一次性写出很好的代码,还是不太容易的。

你可能感兴趣的:(Matrix)