给定一个
m x n的矩阵,如果一个元素为0,则将其所在行和列的所有元素都设为0。请使用原地算法。
解法1 复制矩阵
思路
最简单也是空间消耗最多的办法,就是把矩阵额外复制一份,遍历复制的矩阵,如果遇到 0,就把原矩阵的横和列置为零。
代码
function setZeroes(matrix: number[][]): void {
const m = matrix.length;
const n = matrix[0].length
const copyMatrix: number[][] = [];
for (let i = 0; i < m; i++) {
copyMatrix[i] = [];
for (let j = 0; j < n; j++) {
copyMatrix[i][j] = matrix[i][j];
}
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (copyMatrix[i][j] === 0) {
for (let k = 0; k < n; k++) {
matrix[i][k] = 0; // 行置 0
}
for (let k = 0; k < m; k++) {
matrix[k][j] = 0; // 列置 0
}
}
}
}
};
时空复杂度
时间复杂度:O(mn)
空间复杂度:O(mn)
解法2 数组保存
思路
上个方法是复制了矩阵,其实看一下置零的规律,当出现 0 时,此时矩阵的横和列都需要置零,那我们只需要记录横和列的坐标即可。用一个布尔数组记录横,另一个布尔数组记录列,当遇到零时,数组都标记为 true,最后再根据布尔数组将原矩阵置零。
代码
function setZeroes(matrix: number[][]): void {
const m = matrix.length;
const n = matrix[0].length
const row: boolean[] = new Array(m).fill(false);
const col: boolean[] = new Array(n).fill(false);
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (matrix[i][j] === 0) {
row[i] = true;
col[j] = true;
}
}
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (row[i] || col[j]) {
matrix[i][j] = 0;
}
}
}
};
时空复杂度
时间复杂度:O(mn)
空间复杂度:O(m + n)
解法3 常数空间解法
思路
如果只能使用常数,那么我们可以利用矩阵本身来做标记。
首先标记处首行和首列是否有零,其次如果遇到矩阵中有零,将它的首行和首列标记为零。然后处理这些零,将矩阵内行和列的数字置为零,最后再处理首行和首列有零的情况。
代码
function setZeroes(matrix: number[][]): void {
const m = matrix.length;
const n = matrix[0].length
let firstRowZero = false;
let firstColZero = false;
// 1. 检查第一列是否有 0
for (let i = 0; i < m; i++) {
if (matrix[i][0] === 0) {
firstColZero = true;
break;
}
}
// 2. 检查第一行是否有 0
for (let j = 0; j < n; j++) {
if (matrix[0][j] === 0) {
firstRowZero = true;
break;
}
}
// 3. 使用第一行和第一列作为标记
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
if (matrix[i][j] === 0) {
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
// 4. 根据标记,将相应的行和列置零
for (let i = 1; i < m; i++) {
if (matrix[i][0] === 0) {
for (let j = 1; j < n; j++) {
matrix[i][j] = 0;
}
}
}
for (let j = 1; j < n; j++) {
if (matrix[0][j] === 0) {
for (let i = 1; i < m; i++) {
matrix[i][j] = 0;
}
}
}
// 5. 处理第一行
if (firstRowZero) {
for (let j = 0; j < n; j++) {
matrix[0][j] = 0;
}
}
// 6. 处理第一列
if (firstColZero) {
for (let i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
};
时空复杂度
时间复杂度:O(mn)
空间复杂度:O(1)