95.矩阵置零

一、题目描述

给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

进阶:

一个直观的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
你能想出一个仅使用常量空间的解决方案吗?
在这里插入图片描述
在这里插入图片描述

二、解题思路

思路一:使用额外空间

先来模拟一下置0过程,使用额外的矩阵,每遍历到一个0元素,就在新的矩阵上将这个0元素的行列变为0,下图为遍历到第一个0:
在这里插入图片描述
遍历到第二个0:
在这里插入图片描述
遍历到第三个0:
在这里插入图片描述
使用额外矩阵是因为(以上面矩阵为例),假如在原矩阵上操作,当你遍历到二个0的时候,你不知道这个位置的0是原数组本身这个位置就是0还是因为变化之后置为0的。这种的方法的时空复杂度都是O(mn)

那么来看看怎么降低空间复杂度呢?矩阵置零的核心就是要知道要将矩阵的哪一行哪一列置为0,可以使用两个数组,一个用来记录每一行是否置0,一个用来记录某一列是否置0:
在这里插入图片描述

因为有3行,所以记录置0的数组大小是长度是3,记录列的数组程度是4,初始值都是False。每遍历一个元素都要进行判断,如果是0就将数组相应位置置0,比如第一个元素是0,就将第一行第一列置0,对应记录行置0数组的第1个位置和对应记录列置0数组对应的第一列,然后将其改为true。
在这里插入图片描述
然后我们判断每个元素的行列坐标,行坐标对应行数组索引,列坐标对应列数组索引,如果都为true,则将这个元素置0
在这里插入图片描述
时间复杂度:O(mn)

空间复杂度:O(m+n)

思路二:使用常量级别的空间大小

可以不使用两个数组来记录每行每列是否置0的信息,可以把数组应该存储的信息存储在原始数组的第一列和第一行。
在这里插入图片描述

对于这个数组,我们从逐一开始遍历,当遍历到第一个0元素时,将这个0元素所在行和列的第一个元素置0,表示这一行和列出现了0,需要将这一行和列置0。
在这里插入图片描述
在这里插入图片描述
继续往下遍历,在第三行第三列遇到0,继续将这一行列的首元素置0。
在这里插入图片描述

当有了这些信息之后,如下:
在这里插入图片描述
然后开始从第二行第二列的元素开始遍历,当这个元素所在的行或列中的首元素为0时,将这个元素置0,依次向后遍历,最后如下:
在这里插入图片描述
但是这样也会有一点问题,假设有如下这样的矩阵:
在这里插入图片描述

一个一个元素的遍历,当遇到某个元素为0时,将这个元素的行列首位置0,如下:
在这里插入图片描述
然后,现在从第二行第二列的元素,也就是坐标为(1,1)的元素2开始向后遍历,依次遍历2,5,2,3,0,5;判断每个元素所在行和列的首元素如果是0则将这个元素置为0;最后结果如下:
在这里插入图片描述

但是看上面的原始矩阵,第一行第二列遇到个0,第一行所有元素和第一列所有元素都应该是0,但是最后的结果第一行最后一个元素1没有置0,所以首先将第一行和第一列的所有元素先判断是不是包含0,如果包含就把第一行和第一列元素都置为0;

时间复杂度是:O(mn)

空间复杂度是:O(1)

三、代码演示

思路一代码:

class Solution {
    public void setZeroes(int[][] matrix) {
        //矩阵行大小
        int m = matrix.length;
        //列大小
        int n = matrix[0].length;

        //两个数组用来记录该元素是否为0
        boolean[] rows = new boolean[m];
        boolean[] cols = new boolean[n];

        //遍历每个元素,如果是0,就将该元素对应的行列坐标和数组相应位置设置为true
        for (int row=0; row<m; row++){
            for (int col=0; col<n; col++){
                if (matrix[row][col] == 0){
                    rows[row] = true;
                    cols[col] = true;
                }
            }
        }

        //遍历元素,然后判断该元素对应数组的boolean值
        for (int row=0; row<m; row++){
            for (int col=0; col<n; col++){
                if (rows[row] || cols[col]){
                    matrix[row][col] = 0;
                }
            }
        }
    }
}

思路二代码:

class Solution {
    public void setZeroes(int[][] matrix) {
         //矩阵行大小
        int m = matrix.length;
        //列大小
        int n = matrix[0].length;

        //先判断第一行是否包含0
        boolean flagRow1 = false;
        for (int i=0; i<n; i++){
            //如果包含0,标识一下
            if (matrix[0][i]==0){
                flagRow1 = true;
            }
        }
        //判断第列是否包含0
        boolean flagCol1 = false;
        for (int i=0; i<m; i++){
            //如果包含0,标识一下
            if (matrix[i][0]==0){
                flagCol1 = true;
            }
        }

        //从(1,1)这个元素开始判断,如果这个元素为0,将这个元素的所在行列首元素置0
        for (int row=1; row<m; row++){
            for (int col=1; col<n; col++){
                if (matrix[row][col]==0){
                    matrix[0][col] = 0;
                    matrix[row][0] = 0;
                }
            }
        }

        //此时再从第二行第二列开始遍历
        for (int row=1; row<m; row++){
            for (int col=1; col<n; col++){
                if (matrix[0][col]==0 || matrix[row][0]==0){
                    matrix[row][col] = 0;
                }
            }
        }

        //第一行是否包含0,如果第一行设置为0
        if (flagRow1){
            for (int i=0; i<n; i++){
                //那么将第一行所有元素置为0
                matrix[0][i] = 0;
            }
        }
        //第一列是否包含0,如果第列行设置为0
        if (flagCol1){
            for (int i=0; i<m; i++){
                //那么将第一列所有元素置为0
                matrix[i][0] = 0;
            }
        }
    }
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值