18.矩阵置零

88 阅读3分钟

题目链接

给定一个 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)