• LeetCode73. 矩阵置零


    解法一(使用O(mn)空间)

    可以开一个额外的二维数组,记录每个位置的元素是否已被访问过。

    然后我们遍历原来的二维数组,只要没被访问过且元素为0,那么就将该元素所在的行和列的元素值置为0,
    并且将这一行的所有元素都设置为已经访问过,以免之后的遍历碰到被置为0的元素也将那一行那一列的元素置为0.

    这里要注意,对于一个为0且未被访问的元素所在的行和列的元素置0的时候,要跳过本来就为0的元素,因为可能之后的遍历
    到了其他的本来就为0的元素,由于置了那个元素的状态为访问过,就会跳过这个元素,导致没有将那个元素所在的行和列所在的
    元素置0.

    代码如下:

    class Solution {
    public:
        void setZeroes(vector<vector<int>>& matrix) {
            int rows = matrix.size(), cols = matrix[0].size();      
            vector<vector<bool>> visited(rows, vector<bool>(cols));      //记录每个元素是否已被访问过
            for(int i = 0; i < rows; ++i) {
                for(int j = 0; j < cols; ++j) {
                    if(visited[i][j] == false && matrix[i][j] == 0) {      //只有当元素为0且未被访问过时,才修改这一行这一列的元素
                        for(int k = 0; k < rows; ++k) {
                            if(matrix[k][j] != 0) {                  //这个if判断不能少,目的是为了防止将这一列本来就为0的元素置为已经访问过,导致无法将那个本就为0的元素所在的行和列的元素置0, 下面的if语句同理
                                matrix[k][j] = 0;
                                visited[k][j] = true;
                            }
                        }
                        for(int k = 0; k < cols; ++k) {
                            if(matrix[i][k] != 0) {
                                matrix[i][k] = 0;
                                visited[i][k] = true;
                            }
                        }
                    }
                }
            }
        }
    };
    

    解法二(使用O(m + n)空间)

    给每一个元素都设置一个访问状态需要开二维数组,有点麻烦。

    由于我们只需要把0所在的行和列的元素置为0,所以我们可以这样:遍历一遍数组,如果某个元素为0,
    那么我们记录一下这个元素的行号和列号。

    最后把所有我们记录过的行和列的元素全部置为0即可。

    使用这种方法需要开一个O(n)的数组记录每一行是否有0元素,还要开一个O(m)数组记录每一列是否有0元素。
    因此空间开销是O(m + n)。

    代码如下:

    class Solution {
    public:
        void setZeroes(vector<vector<int>>& matrix) {
            int rows = matrix.size(), cols = matrix[0].size();
            vector<int> rowHasZero(rows), colHasZero(cols);      //两个数组分别记录每一行和每一列是否有0元素
            for(int i = 0; i < rows; ++i) {
                for(int j = 0; j < cols; ++j) {
                    if(matrix[i][j] == 0) {                  //如果某个元素为0,记录下它的行号和列号
                        rowHasZero[i] = 1;
                        colHasZero[j] = 1;
                    }
                }
            }
            for(int i = 0; i < rows; ++i) {      
                if(rowHasZero[i] == 1) {                     //将存在0元素的行的所有元素都置0
                    for(int j = 0; j < cols; ++j) {
                        matrix[i][j] = 0;
                    }
                }
            }
            for(int j = 0; j < cols; ++j) {                  //将存在0元素的列的所有元素都置0
                if(colHasZero[j] == 1) {
                    for(int i = 0; i < rows; ++i) {
                        matrix[i][j] = 0;
                    }
                }
            }
        }
    };
    

    解法三 (使用常数空间)

    由于要将0元素所在的行和列所在的所有元素都置为0,我们就需要记录哪些行哪些列含有0元素,但是又不能开数组记录,那怎么办呢?

    可以考虑直接用原数组记录,比如解法二里开了一个列大小的数组记录每一行是否有0,又开了一个行大小的数组记录每一列是否有0.

    我们可以直接在第0行和第0列记录! 比如,如果martix[i][j]为0,那么我们就让martix[i][0]为0,表示第i行含有元素0,之后需要将该行所有元素都改为0.
    再让martix[0][j]为0,表示第j列含有元素0,之后需要讲该列所有元素都改为0.

    这样我们就不需要额外开数组了,但是又有个问题,这样修改了原来的第0行和第0列的元素,咋办?

    问题不大,只能开常数空间,不代表不能开空间,我们额外用两个变量记录第0行和第0列是否有0,如果有,在最后就将第0行(列)的所有元素改为0,
    如果没有,那么如果第0行或第0列的元素所在的行(列)没有0,那么他们还是原来的值(没有被修改),如果有,那说明(对第0行/列元素的修改)正好改对了呀,
    反正他们最后本来就是0! 这样就解决了空间的问题,使用常数空间就可以将矩阵置0.

    代码如下:

    class Solution {
    public:
        void setZeroes(vector<vector<int>>& matrix) {
            int rows = matrix.size(), cols = matrix[0].size();
            int firstRowHasZero = 0, firstColHasZero = 0;      //判断第0行和第0列是否有元素0
            for(int i = 0; i < cols; ++i) {
                if(matrix[0][i] == 0) {                        //如果第0行有元素0,修改firstRowHasZero,在程序最后将第0行所有元素都改为0
                    firstRowHasZero = 1;
                    break;
                }
            }
            for(int i = 0; i < rows; ++i) {
                if(matrix[i][0] == 0) {                        //如果第0列有元素0,修改firstColHasZero,在程序最后将第0列所有元素都改为0
                    firstColHasZero = 1;
                    break;
                }
            }
            for(int i = 1; i < rows; ++i) {               
                for(int j = 0; j < cols; ++j) {
                    if(matrix[i][j] == 0) {
                        matrix[i][0] = 0;                 //如果某元素为0,修改martix[i][0]为0,表示第i行的元素最后需要全部改为0
                        break;
                    }
                }
            }
            for(int j = 1; j < cols; ++j) {
                for(int i = 0; i < rows; ++i) {
                    if(matrix[i][j] == 0) {
                        matrix[0][j] = 0;                 //如果某元素为0,修改martix[i][0]为0,表示第j列的元素最后需要全部改为0
                        break;
                    }
                }
            }
            for(int i = 1; i < rows; ++i) {
                if(matrix[i][0] == 0) {                  //第i行有0元素,把第i行所有元素都改为0
                    for(int j = 1; j < cols; ++j) {
                        matrix[i][j] = 0;
                    }
                }
            }
            for(int j = 1; j < cols; ++j) {
                if(matrix[0][j] == 0) {                  //第j列有0元素,把第j列所有元素都改为0
                    for(int i = 1; i < rows; ++i) {
                        matrix[i][j] = 0;
                    }
                }
            }
            if(firstRowHasZero) {
                for(int j = 0; j < cols; ++j) {          //第0行有0元素,把第0行所有元素都改为0
                    matrix[0][j] = 0;
                }
            }
            if(firstColHasZero) {
                for(int i = 0; i < rows; ++i) {          //第0列有0元素,把第0列所有元素都改为0
                    matrix[i][0] = 0;
                }
            }
        }
    };
    
  • 相关阅读:
    sqlserver2005分页
    windows计划任务
    sqlserver 2005 通信格式
    sqlserver 导出数据到excel
    所有连接sqlserver 2005 数据库的驱动程序
    Sql 2000 中行转列的查询方法
    [转] ASP.NET中使用javascript
    [转]17种常用正则表达式
    正则式正反向预编译(实战)
    正则表达式的正反向预编译
  • 原文地址:https://www.cnblogs.com/linrj/p/13236435.html
Copyright © 2020-2023  润新知