当前位置: 首页 > news >正文

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

文章目录

🍁前言

🧧一、题目描述

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

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

🦀总结


🍁前言

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


🧧一、题目描述

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

示例 1:

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

 示例 2:

输入: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
  • -2^31 <= matrix[i][j] <= 2^31 - 1

进阶:

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

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

思路:

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

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

  • 但是我们如果单独创建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。

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

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

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

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        // int flag_row0 = false; // 用于标记第一行是否有0,可以用第一列的第一个元素代替,从而减少了一个变量


        int flag_col0 = false; // 用于标记第一列是否有0
        int row = matrix.size(); // 一共有多少行
        int col = matrix[0].size(); // 一共有多少列

        // 遍历一遍矩阵
        // 用第一行和第一列标记矩阵中0元素的坐标
        // 并且判断第一列是否本身就存在0
        for (int i = 0; i < row; ++i)
        {
            // 只要第一列存在一个0,就将第一列标记
            if (!matrix[i][0])
            {
                flag_col0 = true;
            }

            // 标记每个0元素的下标
            // 由于第一列已经单独判断了,所以这里只用从第二列开始遍历
            for (int j = 1; j < col; ++j)
            {
                // 如果当前元素为0,就将它的横纵坐标分别在第一行和第一列中进行标记
                if (matrix[i][j] == 0)
                {
                    // 注意:这里的i为纵坐标,j为横坐标
                    matrix[0][j] = 0; // 第一行用于标记横坐标
                    matrix[i][0] = 0; // 第一列用于标记纵坐标
                }
            }
        }

        // 再遍历一遍矩阵,只要当前元素的横坐标、纵坐标有一个被标记过,就将其置为0
        // 注意:这时遍历时就不能从第一列开始遍历了,如果第一列本身存在0,我们遍历完第一列就将第一列全部置成0了,导致我们刚才标记的坐标改变
        // 所以我们需要从后向前遍历。
        // 每行的第一个元素也要最后判断,如果先判断的话就跟先遍历第一行是一样的了
        // 如果第一列本身存在0,那么从每行第一个元素开始遍历,就会将第一个元素置成0,导致我们标记的坐标改变。

        for (int i = row - 1; i >= 0; --i)
        {
            // 由于下面会单独判断第一列元素,所以这里还是从第二列开始遍历
            for (int j = 1; j < col; ++j)
            {
                // 如果当前元素的横坐标、纵坐标有一个被标记过,就将其置为0
                if (!matrix[0][j] || !matrix[i][0])
                {
                   matrix[i][j] = 0;
                }
            }

            // 判断第一列是否本身就有0,如果有就将第一列的元素置成0,如果没有就不管了
            if (flag_col0)
            {
                 matrix[i][0] = 0;
            }
        }
    }
};

🦀总结

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

相关文章:

  • JSR223常用函数和对象--Jmeter内置对象Chapter1
  • 从头开始训练神经网络(Unet)
  • Python制作自动填写脚本,100%准确率
  • 半小时了解SQL注入漏洞?(注入方式大全+绕过大全)
  • CSS 几种常见的选择器
  • 【Day17】Java算法刷题 【面试题 01.08. 零矩阵】 【844. 比较含退格的字符串】
  • 【C++游戏引擎Easy2D】Random随机数,不同于Rand,做游戏必备
  • 【小程序入门】App函数注册小程序实例
  • 【Linux从0到1】第十七篇:高级IO
  • 一起来做个CH347的项目(应用于FPGA、CPLD、MCU)
  • 特征筛选还在用XGB的Feature Importance?试试Permutation Importance
  • 06-ServletRequest
  • Spring Cloud Alibaba系列之nacos:(4)配置管理
  • 一篇五分生信临床模型预测文章代码复现——Figure 3. 基因富集分析(二)
  • 深度学习——day34 读论文:深度 ReLU 网络在特征提取和泛化中的深度选择(2022 Q1)
  • 「面试题」如何实现一个圣杯布局?
  • 【Linux系统编程】快速查找errno错误码信息
  • Apache的基本使用
  • CSS实用技巧干货
  • jdbc就是这么简单
  • Laravel 实践之路: 数据库迁移与数据填充
  • Redash本地开发环境搭建
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • Service Worker
  • socket.io+express实现聊天室的思考(三)
  • 浮动相关
  • 简单易用的leetcode开发测试工具(npm)
  • 配置 PM2 实现代码自动发布
  • 说说动画卡顿的解决方案
  • 《天龙八部3D》Unity技术方案揭秘
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​什么是bug?bug的源头在哪里?
  • #100天计划# 2013年9月29日
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (办公)springboot配置aop处理请求.
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (三)docker:Dockerfile构建容器运行jar包
  • (三分钟)速览传统边缘检测算子
  • (十五)使用Nexus创建Maven私服
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .FileZilla的使用和主动模式被动模式介绍
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .net快速开发框架源码分享
  • .net知识和学习方法系列(二十一)CLR-枚举
  • @Autowired和@Resource的区别
  • @Documented注解的作用
  • @Import注解详解
  • [Android Studio] 开发Java 程序
  • [CakePHP] 在Controller中使用Helper