【面试经典150 | 矩阵】矩阵置零

文章目录

  • 写在前面
  • Tag
  • 题目来源
  • 题目解读
  • 解题思路
    • 方法一: O ( m n ) O(mn) O(mn) 空间复杂度
    • 方法二: O ( m + n ) O(m+n) O(m+n) 空间复杂度
    • 方法三:仅使用2个额外变量的常量空间复杂度
  • 写在最后

写在前面

本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……

专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:

  • Tag:介绍本题牵涉到的知识点、数据结构;
  • 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
  • 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
  • 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
  • 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。

Tag

【矩阵】【数组】


题目来源

73. 矩阵置零


题目解读

将矩阵中 0 元素的那一行和那一列所有元素都置为 0


解题思路

方法一: O ( m n ) O(mn) O(mn) 空间复杂度

最朴素的方法也是最简单的方法就是使用一个大小和原数组一样的数组作为答案数组 res,当 matrix[i][j] 等于 0 时,更新 resij 列 元素均为 0

实现代码

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();

        multimap<int, int> hash;

        int i, j, k;
        for(i = 0; i < m; ++i){
            for(j = 0; j < n; ++j){
                if(matrix[i][j] == 0){
                    hash.insert({i, j});
                }
            }
        }

        for(auto [a, b] : hash){
             // 行
            for(k = 0; k < n; ++k){
                matrix[a][k] = 0;
            }
            // 列
            for(k = 0; k < m; ++k){
                matrix[k][b] = 0;
            }
        }
    }
};

复杂度分析

时间复杂度: O ( m n ) O(mn) O(mn) m m m 为矩阵 matrix 的行数, n n n 为矩阵的列数。

空间复杂度: O ( m n ) O(mn) O(mn),使用的额外空间为 multimap,最大需要容纳矩阵中的所有位置。

方法二: O ( m + n ) O(m+n) O(m+n) 空间复杂度

我们可以用数组 row 来记录矩阵某一行中是否有 0,用数组 col 来记录矩阵中某一列是否有 0

首先,遍历一遍矩阵来更新数组 rowcol,最后根据数组 rowcol 中的值来更新矩阵的值。具体地,对于位置 (i, j),如果有 row[i] = 1 或者 col[j] = 1,则更新 matrix[i][j] = 0

实现代码

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<int> row(m), col(n);
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == 0) {
                    row[i] = 1;
                    col[j] = 1;
                }
            }
        }

        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (row[i] == 1 || col[j] == 1) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
};

复杂度分析

时间复杂度: O ( m n ) O(mn) O(mn) m m m 为矩阵 matrix 的行数, n n n 为矩阵的列数。

空间复杂度: O ( m + n ) O(m+n) O(m+n)

方法三:仅使用2个额外变量的常量空间复杂度

我们可以用矩阵的第一行和第一列代替方法一中的两个标记数组,以达到 O ( 1 ) O(1) O(1) 的额外空间。但这样会导致原数组的第一行和第一列被修改,无法记录它们是否原本包含 0。因此我们需要额外使用两个标记变量分别记录第一行和第一列是否原本包含 0

在实际代码中,我们首先预处理出两个标记变量,接着使用其他行与列去处理第一行与第一列,然后反过来使用第一行与第一列去更新其他行与列,最后使用两个标记变量更新第一行与第一列即可。

实现代码

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();

        int i, j;
        int row0 = 0, col0 = 0;
        // 第一列
        for(i = 0; i < m; ++i){
            if(matrix[i][0] == 0){
                col0 = 1;
            }
        }
        // 第一行
        for(j = 0; j < n; ++j){
            if(matrix[0][j] == 0){
                row0 = 1;
            }
        }

        for(i = 1; i < m; ++i){
            for(j = 1; j < n; ++j){
                if(matrix[i][j] == 0){
                    matrix[i][0] = matrix[0][j] = 0;
                }
            }
        }

        for(i = 1; i < m; ++i){
            for(j = 1; j < n; ++j){
                if(!matrix[i][0] || !matrix[0][j]){
                    matrix[i][j] = 0;
                }
            }
        }

        if(col0){
            for(i = 0; i < m; ++i){
                matrix[i][0] = 0;
            }
        }
        if(row0){
            for(j = 0; j < n; ++j){
                matrix[0][j] = 0;
            }
        }
    }
};

复杂度分析

时间复杂度: O ( m n ) O(mn) O(mn) m m m 为矩阵 matrix 的行数, n n n 为矩阵的列数。

空间复杂度: O ( 1 ) O(1) O(1)


写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 哦。

你可能感兴趣的:(面试经典150题,矩阵,数组)