• LeetCode高频题73. 矩阵置零


    LeetCode高频题73. 矩阵置零

    提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
    互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
    你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
    在这里插入图片描述


    题目

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


    一、审题

    示例:1
    在这里插入图片描述
    输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
    输出:[[1,0,1],[0,0,0],[1,0,1]]

    在这里插入图片描述
    输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
    输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

    提示:

    m == matrix.length
    n == matrix[0].length
    1 <= m, n <= 200
    -231 <= matrix[i][j] <= 231 - 1

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/set-matrix-zeroes
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


    最简单的就是外部辅助空间记录哪些行和列,需要变0

    当然,你遍历过程中,遇到0,不能立马改整行和整列,否则你待会不知道遇到的0是怎么来的

    用一个行哈希表,列哈希表,记录哪些行,哪些列应该直接变零
    耗费额外空间的

    代码也很简单

            //复习:
            public void setZeroesReview(int[][] matrix) {
                if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return;
    
                int N = matrix.length;
                int M = matrix[0].length;
    
                //辅助
                HashSet<Integer> rowSet = new HashSet<>();
                HashSet<Integer> columnSet = new HashSet<>();
    
                //遍历
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < M; j++) {
                        if (matrix[i][j] == 0){
                            rowSet.add(i);
                            columnSet.add(j);
                        }
                    }
                }
    
                //再修改
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < M; j++) {
                        if (rowSet.contains(i)) matrix[i][j] = 0;
                        if (columnSet.contains(j)) matrix[i][j] = 0;
                    }
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    测试;

        public static void test(){
            Solution solution = new Solution();
            int[][] arr = {
                    {1,1,2,4},
                    {3,1,5,2},
                    {0,3,1,1},
                    {1,3,1,0}};
            solution.setZeroes(arr);
            for (int i = 0; i < arr.length; i++) {
                for (int j = 0; j < arr[0].length; j++) {
                    System.out.print(arr[i][j] +" ");
                }
                System.out.println();
            }
    
            System.out.println();
            int[][] arr2 = {
                    {1,1,2,4},
                    {3,1,5,2},
                    {0,3,1,1},
                    {1,3,1,0}};
            solution.setZeroesReview(arr2);
            for (int i = 0; i < arr2.length; i++) {
                for (int j = 0; j < arr2[0].length; j++) {
                    System.out.print(arr2[i][j] +" ");
                }
                System.out.println();
            }
    
        }
    
        public static void main(String[] args) {
            test();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    结果:

    0 1 2 0 
    0 1 5 0 
    0 0 0 0 
    0 0 0 0 
    
    0 1 2 0 
    0 1 5 0 
    0 0 0 0 
    0 0 0 0 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    LeetCode测试:
    在这里插入图片描述
    在这里插入图片描述

    外部辅助首先耗费空间
    其次时间也挺慢

    题目说了用:原地算法 搞

    咱们来一波节约空间和时间的做法

    我们想干啥呢??
    用第0行来记录,这一行,是否要整体变0???
    用第0列来记录,这一列,是否要整体变0???
    在这里插入图片描述

    如果遍历过程中,发现某一行i需要变0,那i行0列这个格子就要记录
    如果遍历过程中,发现某一列j需要变0,那0行j列这个格子就要记录

    那注意了
    你万一第0行,需要整体变0,怎么记录,单独拿一个变量row0来记录,
    你万一第0列,需要整体变0,怎么记录,单独拿一个变量column0来记录,

    咱们一开始就先遍历0行,如果遇到0,row0=true
    咱们一开始就先遍历0列,如果遇到0,column0=true
    在这里插入图片描述
    然后遍历i=1–N-1行,遍历j=1–M-1列,用第0行和0列记录
    用0记录,回头你检查,不是0的都不要动,是0的整行,或者整列都得变0

    然后变的时候,当然是根据0行和0列先搞0–N-1行和0–M-1列【注意这可是整个矩阵的行列都变哦】
    然后检查row0和column0,决定整个0行和0列要不要变

    这就是原地算法的意思
    手撕代码:

            //如果遍历过程中,发现某一行i需要变0,那i行0列这个格子就要记录
            //如果遍历过程中,发现某一列j需要变0,那0行j列这个格子就要记录
            public void setZeroesSource(int[][] matrix) {
                if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return;
    
                int N = matrix.length;
                int M = matrix[0].length;
    
                //俩变量记录
                //咱们一开始就先遍历0行,如果遇到0,row0=true
                //咱们一开始就先遍历0列,如果遇到0,column0=true
                boolean row0 = false;
                boolean column0 = false;
                for (int i = 0; i < N; i++) {
                    if (matrix[i][0] == 0) column0 = true;
                }
                for (int j = 0; j < M; j++) {
                    if (matrix[0][j] == 0) row0 = true;
                }
                //然后遍历i=1--N-1行,遍历j=1--M-1列,用第0行和0列记录
                //用2记录,回头你检查,不是2的都不要动,是2的整行,或者整列都得变0
                for (int i = 1; i < N; i++) {
                    for (int j = 1; j < M; j++) {
                        if (matrix[i][j] == 0) {
                            matrix[i][0] = 0;
                            matrix[0][j] = 0;//对应俩格子记录0,代表这一行,这一列都得是0
                        }
                    }
                }
    
                //然后变的时候,当然是根据0行和0列先搞1--N-1行和1--M-1列
                //然后检查row0和column0,决定整个0行和0列要不要变
                for (int i = 1; i < N; i++) {
                    for (int j = 1; j < M; j++) {
                        if (matrix[i][0] == 0) matrix[i][j] = 0;//这一行都得是0
                        if (matrix[0][j] == 0) matrix[i][j] = 0;//这一列都得是0
                    }
                }
                if (row0)
                    for (int j = 0; j < M; j++) {
                        matrix[0][j] = 0;
                    }
                if (column0)
                    for (int i = 0; i < N; i++) {
                        matrix[i][0] = 0;
                    }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    测试

            System.out.println();
            int[][] arr3 = {
                    {1,1,2,4},
                    {3,1,5,2},
                    {0,3,1,1},
                    {1,3,1,0}};
            solution.setZeroesSource(arr3);
            for (int i = 0; i < arr3.length; i++) {
                for (int j = 0; j < arr3[0].length; j++) {
                    System.out.print(arr3[i][j] +" ");
                }
                System.out.println();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    很OK

    0 1 2 0 
    0 1 5 0 
    0 0 0 0 
    0 0 0 0 
    
    • 1
    • 2
    • 3
    • 4

    LeetCode测试:
    在这里插入图片描述
    在这里插入图片描述
    看看,整个空间,直接就大大地优化了

    不过速度咋还慢呢???
    不管,因为LeetCode有时候记录时间就是不准的,这已经是最好的算法了。


    总结

    提示:重要经验:

    1)用辅助空间势必耗费额外空间
    2)这种记录要变0或者1的事,可以原地记录,简单几个变量就行
    3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

  • 相关阅读:
    JavaEE 进阶:Spring 的创建和使用
    若依快速上手
    PlantUML入门教程:画时序图
    旋转图片和坐标变换
    2022-mac系统,系统各个文件夹的的含义,防止有些同学误删
    Android12.0 系统限制上网系列之iptables用IOemNetd实现app上网黑名单的实现
    Spring框架的未来:Spring 6的新特性预览
    o.s.b.d.LoggingFailureAnalysisReporter 错误解决方法
    数据结构之双向链表
    DMT信号光纤传输的数字信号处理
  • 原文地址:https://blog.csdn.net/weixin_46838716/article/details/126174040