赞
踩
给定一个 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; } } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。