需求:
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;
}
}