题目地址:
https://leetcode.com/problems/set-matrix-zeroes/
给定一个矩阵,将其中的含有 的行和列全部置零。
法1:容易想到的方法是,用一个数据结构来记录哪些行和哪些列需要置零,最后统一置零即可。此处可以用两个哈希表。代码如下:
import java.util.Arrays;
import java.util.HashSet;
public class Solution {
public void setZeroes(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return;
}
// rows记录哪些行需要置零,cols记录哪些列需要置零
HashSet<Integer> rows = new HashSet<>(), cols = new HashSet<>();
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == 0){
rows.add(i);
cols.add(j);
}
}
}
// 最后统一置零
for (Integer row : rows) {
Arrays.fill(matrix[row], 0);
}
for (Integer col : cols) {
for (int i = 0; i < matrix.length; i++) {
matrix[i][col] = 0;
}
}
}
}
时间复杂度 ,空间复杂度 , 和 分别为行数和列数。
法2:如果不用额外空间的话,直观的想法是,直接用原矩阵来记录需要置零的行或者列这个信息。比如,我们可以对每一个需要置零的行和列的第一个元素来做标记,之后在update矩阵的时候,就check一下当前行或者列是否做了标记,如果做了标记就置零,否则就跳过。之后还需要check一下第一行和第一列是否需要置零。代码如下:
import java.util.Arrays;
public class Solution {
public void setZeroes(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return;
}
// 标记第0行和第0列是否需要置零
boolean row0 = false, col0 = false;
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[0][j] == 0) {
row0 = true;
break;
}
}
for (int i = 0; i < matrix.length; i++) {
if (matrix[i][0] == 0) {
col0 = true;
break;
}
}
// 接下来开始利用第0行和第0列来记录本行或者本列最终是否需要置零
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 = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
// 最后更新第0行和第0列
if (row0) {
Arrays.fill(matrix[0], 0);
}
if (col0) {
for (int i = 0; i < matrix.length; i++) {
matrix[i][0] = 0;
}
}
}
}
时间复杂度一样,空间 。
算法正确性证明:
先想象原矩阵除去第
行和第
列构成的矩阵,我们只把第
行和第
列当成标记用途的行,那么接下来遍历剩下的矩阵的时候,就可以利用那两行做标记,很显然剩下的矩阵中某个位置置零,当且仅当它的所在行或者所在列被做过标记。接下来再更新第
行和第
列即可。