• 【每日一好题】这么经典的题你不能不会:矩阵置零


     

    大家好啊,我是不一样的烟火a,今天我要为大家分享一道好题,这道题也是一道常考题,所以大家务必掌握哦。为了避免以后忘了时再想看就找不到了,所以建议收藏。🦀最后提前祝大家国庆节快乐。


    🧧一、题目描述

    给定一个 m x n  的矩阵,如果一个元素为 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 

     

    示例 1:

    eff14a2c31004fe09361dfb1d3795be5.png

     

    1. 输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
    2. 输出:[[1,0,1],[0,0,0],[1,0,1]]

     示例 2:

    8078127584b64f92a87a33719aa3b45f.png

    1. 输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
    2. 输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

     提示:

    • m == matrix.length
    • n == matrix[0].length
    • 1 <= m, n <= 200
    • -2^31 <= matrix[i][j] <= 2^31 - 1

     

    进阶:

    • 一个直观的解决方案是使用  O(mn) 的额外空间,但这并不是一个好的解决方案。
    • 一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
    • 你能想出一个仅使用常量空间的解决方案吗?

    快速跳转题目:矩阵置零

    🏮二、思路解析(最优解法)

    思路:

    • 我们可以用两个数组分别标记矩阵里面0元素的横坐标和纵坐标。我们用两个数组的下标来代替矩阵里面0元素的下标即可,把两个数组的某个位置的元素置为0即为标记。我们遍历一遍矩阵,遇到0元素,我们就将两个数组对应下标位置设为0进行标记。

    a8e5461e97cd4406aa993ad43df00f98.png

     

    • 我们将矩阵中所有0元素的横纵坐标都标记后,我们这时再遍历一遍矩阵,如果发现当前元素的横坐标或者纵坐标被标记过,那么就将当前元素设置为0。

    1bf2ccb218544d129a32c2a220105e3b.png

     

    • 但是我们如果单独创建2个数组来标记0元素的横纵坐标的话,空间复杂度就为O(m + n) 了,所以我们可以直接将矩阵的第一行用来标记0元素的横坐标,用矩阵的第一列来标记0元素的纵坐标。这样就可以将空间复杂度降为O(1)了。但是我们这时又需要考虑第一行或者第一列是否本身就存在0元素,如果第一行或第一列本身就存在0元素,我们就要将第一列或第一行的所有元素置为0,所以我们需要设置2个flag来标记一下第一行和第一列是否本身就存在0元素。如果我们再想一想,就可以发现,我们其实只用设置一个flag来标记第一列是否本身就存在0元素即可,因为第一列的第一个元素就可以当flag用,如果第一行本身存在0元素,我们在遍历第一行的时候就会将第一列第一个元素标记为0,这样就节省了一个变量的大小。

    解题步骤:

    1.初始状态:由于第一列中本身就存在0元素,所以我们将flag设置为true,到最后我们就会将第一列所有元素置成0。

    a8e54e3f8c2045189190a4a018e5001f.png

     

    2.我们用第一列和第一行来标记0元素的横纵坐标。

    8b7cd46e3c9f4a36a1519f0acbf5cd5e.png

     

    3.我们从最后一行,每行的第二列开始遍历矩阵,只要当前元素的横纵坐标有一个被标记,我们就将当前元素置为0。(为什么要从最后一行开始遍历:我们遍历的时候需要从最后一行向上遍历,不要忘我们第一行是用来标记0元素的横坐标的,如果从第一行开始遍历,就有可能将标记的0元素横坐标改变。为什么要从第二列开始遍历:同样第一列是用来存储0元素的纵坐标的,所以我们等一行的其他列都遍历完后再回过头来看第一列,当一行的其他列都遍历完,最后我们判断flag是否为true,也就是判断第一列原本有没有0元素存在,如果flag为true,那么我们就将第一列的元素置为0。)

    e0e8de0e5837434b9b1c6b065e97ac0f.png

    🧨三、代码实现(内有超详细的注释)

    1. class Solution {
    2. public:
    3. void setZeroes(vectorint>>& matrix) {
    4. // int flag_row0 = false; // 用于标记第一行是否有0,可以用第一列的第一个元素代替,从而减少了一个变量
    5. int flag_col0 = false; // 用于标记第一列是否有0
    6. int row = matrix.size(); // 一共有多少行
    7. int col = matrix[0].size(); // 一共有多少列
    8. // 遍历一遍矩阵
    9. // 用第一行和第一列标记矩阵中0元素的坐标
    10. // 并且判断第一列是否本身就存在0
    11. for (int i = 0; i < row; ++i)
    12. {
    13. // 只要第一列存在一个0,就将第一列标记
    14. if (!matrix[i][0])
    15. {
    16. flag_col0 = true;
    17. }
    18. // 标记每个0元素的下标
    19. // 由于第一列已经单独判断了,所以这里只用从第二列开始遍历
    20. for (int j = 1; j < col; ++j)
    21. {
    22. // 如果当前元素为0,就将它的横纵坐标分别在第一行和第一列中进行标记
    23. if (matrix[i][j] == 0)
    24. {
    25. // 注意:这里的i为纵坐标,j为横坐标
    26. matrix[0][j] = 0; // 第一行用于标记横坐标
    27. matrix[i][0] = 0; // 第一列用于标记纵坐标
    28. }
    29. }
    30. }
    31. // 再遍历一遍矩阵,只要当前元素的横坐标、纵坐标有一个被标记过,就将其置为0
    32. // 注意:这时遍历时就不能从第一列开始遍历了,如果第一列本身存在0,我们遍历完第一列就将第一列全部置成0了,导致我们刚才标记的坐标改变
    33. // 所以我们需要从后向前遍历。
    34. // 每行的第一个元素也要最后判断,如果先判断的话就跟先遍历第一行是一样的了
    35. // 如果第一列本身存在0,那么从每行第一个元素开始遍历,就会将第一个元素置成0,导致我们标记的坐标改变。
    36. for (int i = row - 1; i >= 0; --i)
    37. {
    38. // 由于下面会单独判断第一列元素,所以这里还是从第二列开始遍历
    39. for (int j = 1; j < col; ++j)
    40. {
    41. // 如果当前元素的横坐标、纵坐标有一个被标记过,就将其置为0
    42. if (!matrix[0][j] || !matrix[i][0])
    43. {
    44. matrix[i][j] = 0;
    45. }
    46. }
    47. // 判断第一列是否本身就有0,如果有就将第一列的元素置成0,如果没有就不管了
    48. if (flag_col0)
    49. {
    50. matrix[i][0] = 0;
    51. }
    52. }
    53. }
    54. };

    🦀总结

    今天分享的题就到这了,相信大家都能够看懂,如果大家有什么解决不了的问题,欢迎大家评论区留言或者私信告诉我。如果感觉对自己有用的话,可以点个赞或关注鼓励一下博主,我会越做越好的,感谢各位的支持。🦀最后再次祝大家国庆节快乐。

    901b647aff254d83abe29eeb8c67cfc2.gif

     

  • 相关阅读:
    1 Java内存区域管理
    Taurus.MVC WebAPI 入门开发教程5:控制器安全校验属性【HttpGet、HttpPost】【Ack】【Token】【MicroService】。
    2021年6月青少年软件编程(Python)等级考试试卷(一级)
    网络工程类面试非技术问题
    机器学习是什么
    FastReport .NET能够从JasperReports转换文档和报告
    JAVA微信小程序美食菜谱系统毕业设计 开题报告
    10.26~10.27论文,ALP: AdaptiveLossless floating-Point Compression
    prometheus监控JAVA应用(JVM等)并自定义监控指标
    log4j2原理分析及漏洞复现CVE-2021-44228
  • 原文地址:https://blog.csdn.net/qq_64042727/article/details/127124543