面试经典150题——矩阵置零

​"Dream it. Wish it. Do it." - Unknown

brown wooden hand rail with view of beach

1. 题目描述

2.  题目分析与解析

2.1 思路一——暴力求解

思路一很简单,就是尝试遍历矩阵的所有元素,如果发现值等于0,就把当前行与当前列的值分别置为0。同时我们需要注意,因为如果出现下图所示的情况:

比如发现matrix[0][0]等于0,我们把第一列和第一行置为0,但是被置为0的行的最后一个元素如上红色框原本也为0,所以这一行与列也要置为0,如果我们单纯把当前行与列覆盖就不知道原来的位置是什么值。并且如果不使用额外空间,我们比如把某一行某一列都置为了0,那么我们在后续遍历时发现这一行这一列的所有元素都为0,都需要处理,那肯定是错误的。所以这就要求我们必须把原始矩阵存储起来。使用额外的O(MN)空间。

2.2 思路二——优化

因为题目中告诉我们仅需要把是matrix中值为0的所在行与所在列元素置为0,那么如果要减少额外的空间使用,我们是不是就可以先遍历matrix单独只存储为0的部分的行列值,然后再将这些为0的值的行列一个个设置为0?这样使用的额外空间就是根据矩阵中为0的元素的个数来计算的。

但是想象一下最坏的情况,如果所有矩阵元素都为0,那么我们是不是就需要M*N个行列,也就是 M*N*2的额外空间大小,那不是还没第一种方法用的额外空间小?

但是如果我们不存储行与列,而是存储当前行与列是否需要置为0的真假,可不可以?如果我们遇到某一个值为0,那么我们就将两个数组的对应第 i 和第二个数组的第 j 个位置置为true,表示我们 i 行,j 列需要置为0,那么即使后续遍历到了其它在当前行或者当前列的某一个值为0的元素,通过查看数组,肯定有一个值为true,只需要把它所单独在的行或者列对应数组的位置置为true就可以。

所以本质上这种方法就是采用两个数组,来表示哪一行需要置为0,哪一列需要置为0。然后再根据数组的真假,将对应行与列置为0。

这种方法会使用O(m + n) 的额外空间。

2.3 思路三——优化2

因为题目提示了

  • 你能想出一个仅使用常量空间的解决方案吗?

那说明肯定有更好的方案,所以我们再想一想。

抓住问题的本质,我们问题的本质不是找哪个元素的值为0,我们的本质是需要将值为0的行于列的元素置为0。并且以前都是空间换时间,现在想要减小空间,那么是不是可以用时间换空间?

根据我的理解,时间与空间实际上就是对于信息的存储形式,而信息总量不变,因此时间增大那么空间就肯定可以变小,时间减小那么额外的信息就需要使用空间来存储。(当然这要建立在完美的算法上,并且也仅仅是个人的理解)

因此我们是不是可以直接不存储那个元素为0,我们只需要一行行遍历矩阵,发现某个元素为0,记录下它所在的列,等到改行遍历完毕,回过头把该行置为0(如果改行有0元素)。在遍历后续行的时候,我们就可以根据前面发现值为0的列将对应位置直接置为0。

代码思路:

  1. 初始化一个数组,用来记录需要置为0的列

  2. 遍历矩阵的第一行,发现值为0的元素,就将列值加入数组(如果数组不包含该列的话),然后再将该行所有元素赋值为0

  3. 如果该行没有值为0的元素,就直接遍历下一行

  4. 最后遍历column数组,将matrix的第j列的所有元素置为0

这样使用的空间:使用 ArrayList 来存储需要置0的列索引:O(N),在最坏的情况下,如果矩阵的每一列都至少有一个0,则需要存储所有列的索引。

2.4 思路四——优化3

这是我看官方的解析,官方很巧妙的将矩阵的第一行与第一列当作判定数组。其实本质上就和前面的思路2一样,采用两个数组,来表示哪一行需要置为0,哪一列需要置为0,但是这两个数组是用的矩阵原始的第一行与第一列。我将代码加了注释,所以直接读代码应该很清晰:

  • 同时需要注意,有些人会问如果第一行或者第一列根本没有0,那你再用它当标志位,之前的值怎么办?

  • 所以我需要解释一下:之所以使用第一行与第一列无需再存储它之前的值是因为我们仅仅修改在发现当前行者当前列为0的地方,也就是其它位置我是不动的,如下:

  • 当我发现蓝色位置为0,我只更改红色位置的值,这些位置即使第一行与第一列没有0,也是需要更改的。而在结束时如果根据两个判定变量发现第一行与第一列本来没有0,就不需要在做更改了,因为根本没有更改不需要更改的部分。

可以看出这种方法效率还是很高的。

2.5 思路五——优化4

按照上面的官方解析,那就再把思路三种的ArrayList放在矩阵第一行,那也可以使用更少的空间。说做就做,在看了思路三的基础上直接看下面的代码吧

2.6 思路六——优化5——只使用一个变量

在思路五的基础上,我们的判断当前行是否需要置为0的flag是可以省略掉的,如下:

注意这一行:

将该行第一个元素当作一个标志位,判断是否需要将该行的元素置为0

(如果该行某个元素为0,那么将该行的所有元素应该置为0,因此无所谓用该行哪个元素当标志位都是可以的)

按照这种思路只需要使用一个布尔变量就可以完成任务,还是很巧妙的。

3. 代码实现

3.1 思路一

3.2 思路二

3.3 思路三

思路四五六见上

4. 相关复杂度分析

1. 暴力求解

  • 时间复杂度: (O(M^2N + MN^2))。因为对于矩阵中的每一个元素,都可能需要遍历整行和整列来将它们置为0。

解释:

  • 空间复杂度: (O(MN))。需要一个同样大小的矩阵来存储副本。

2. 优化

  • 时间复杂度: (O(MN))。首先遍历一遍矩阵来标记需要置0的行和列,然后根据这些标记来置0,每个步骤都是线性的。

  • 空间复杂度: (O(M + N))。使用两个额外的数组来记录需要置0的行和列。

3. 优化2

  • 时间复杂度: (O(MN^2))。最坏情况下,对于矩阵的每一个元素,都可能需要遍历整个列索引列表来检查是否已经记录了该列。

  • 空间复杂度: (O(N))。使用一个ArrayList来记录需要置0的列。

4. 优化3

  • 时间复杂度: (O(MN))。遍历整个矩阵两次,一次用于标记,一次用于实际置0操作。

  • 空间复杂度: (O(1))。利用矩阵的第一行和第一列来记录0的位置,除了两个额外的标志位以外不需要其他额外空间。

5. 优化4

  • 时间复杂度: (O(MN))。虽然有多次遍历,但每次遍历都是线性的,关键操作还是依赖于矩阵的总元素数量。

  • 空间复杂度: (O(1))。仅使用一个额外的标志位来记录第一行是否需要置0,直接在原矩阵上操作。

6. 优化5

  • 时间复杂度: (O(MN))。和前一种方法类似,遍历矩阵来标记0的位置,然后根据这些标记来置0。

  • 空间复杂度: (O(1))。使用矩阵的第一行和第一个元素来记录行和列是否需要置0,没有使用其他额外空间。

但显然,随着优化的进行,我们尽量减少了空间复杂度,直至达到常数空间复杂度的解法,同时保持了时间复杂度为线性。总之来说还是很有意思的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/709887.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java】基本数据类型、包装类与字符串间的转换 例题

写在前面: 关于这道题,初见感觉有点cpu烧坏了,准确来说是看了网上的一些讲解都感觉不尽人意。自己整理了一下,希望能帮助到大家。 题目: 如下两个题目输出结果相同吗?各是什么。 Object o1 true ? new…

java演唱会网上订票购票系统springboot+vue

随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的交换和信息流通显得特别重要。因此,开发合适的基于springboot的演唱会购票系统的设计与实现成为企业必然要走…

基于uniapp开发小程序,代码上线发布教程【抖音、微信】

本系列文章适合三类同学:1.希望学习小程序开发;2.希望无代码、低代码拥有自己的小程序;3.快速搭建小程序交作业、交毕设的大学生 本系列文章将推出配套桌面端软件,配合软件,可实现傻瓜式开发小程序,请有需求…

@Slf4j 变量log找不到符号,可能是 Gradle 配置文件写得有问题

Slf4j 变量log找不到符号 鄙人在学习 Java 的 spring boot 项目时, 常常因为 maven 配置文件使用 xml 格式过于复杂, 所以更倾向于使用 gradle 作为构建工具. 然而, 在使用 gradle 作为构建工具时, 又需要引用 Lombok 依赖. 有时忘记在初始化项目时添加上 Lombok 依赖, 所以经…

C++ deque详解以及容器适配器

目录 1.容器适配器 2.deque的使用 2.1deque的介绍 2.2deque的缺陷 2.3deque作为stack和queue的可行性 2.4 deque类的使用 2.4.1deque的构造函数 2.4.2deque容量操作 2.4.3deque赋值,插入 1.容器适配器 适配器是一种设计模式(设计模式是一套被人…

idea创建一个简单的maven项目

个人学习笔记(整理不易,有帮助点个赞) 笔记目录:学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 添加-DarchetypeCataloginternal 运行参数 (ps:不填的话,maven 骨架生成速度缓慢) 其实我没…

Redis---持久化

Redis是内存数据库,是把数据存储在内存中的,但是内存中的数据不是持久的,如果想要做到持久,那么就需要让redis将数据存储到硬盘上。 Redis持久化有两种策略: RDB > Redis DataBase RDB机制采取的是定期备份AOF …

c# ABB 机械手上位机连接

c# 程式开发和调试步骤如下: ABB 机械手要开启PC Interface功能。ABB 机械手设定ip地址。设定测试笔记本和机械手同一网段,用网线直连机械手,也可以通过交换机连接机械手。确保笔记本能够ping通和telnet 机械手80端口都是OK的。以上都OK的话…

QT C++实践|超详细数据库的连接和增删改查操作|附源码

0:前言 🪧 什么情况需要数据库? 1 大规模的数据需要处理(比如上千上万的数据量)2 需要把数据信息存储起来,无论是本地还是服务上,而不是断电后数据信息就消失了。 如果不是上面的原因化,一般…

是谁家的小千金跑出来了?

古典的山树绣花设计 精致典雅,上身立体又轻盈 做了粉绿两色,很适合春天的氛围 春天是个适合外出游玩的季节 穿上这件出游真的超美,日常穿也可 超出片很吸睛!

Pytorch学习 day01(Jupyter安装

Jupyter 安装过程中遇到的问题: Anaconda的base环境会自动安装Jupyter,但是如果我们要在其他环境中安装Jupyter,就需要注意,该环境的python版本不能高于3.11,且用以下代码安装: conda install nb_conda_…

消息中间件之RocketMQ源码分析(二十三)

Broker的关机恢复机制 概述 Broker关机恢复是指恢复CommitLog、Consume Queue、Index File等数据文件。Broker关机分为正常调用命令关机和异常被迫进程终止关机两种情况。恢复过程的设计目标是使正常停止的进程实现零数据丢失,异常停止的进程实现最少量的数据丢失…

Groovy - 大数据共享搜索配置

数据共享搜索列中配置了搜索列,相应的数据共享接口中也需要支持根据配置的字段搜索,配置实体时,支持搜索的入参code必须是searchKeys,且接口应该是需要支持分页(入参必须是 current、pageSize)的。current …

Linux系统Docker部署Nexus Maven并实现远程访问本地管理界面

文章目录 1. Docker安装Nexus2. 本地访问Nexus3. Linux安装Cpolar4. 配置Nexus界面公网地址5. 远程访问 Nexus界面6. 固定Nexus公网地址7. 固定地址访问Nexus Nexus是一个仓库管理工具,用于管理和组织软件构建过程中的依赖项和构件。它与Maven密切相关,可…

SpringBoot多数据源配置(MySql、Oracle)

一、依赖 <!-- dynamic-datasource 多数据源--><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId></dependency><!--oracle驱动--><dependency><groupI…

JavaScript高级程序设计

前言 《JavaScript高级程序设计》 第1章——什么是JavaScript DOM将整个页面抽象为一组分层节点。 BOM用于支持访问和操作浏览器的窗口。 第2章——HTML中的JavaScript 2.1 < script >元素 元素描述async立即开始下载脚本&#xff0c;但不能阻止其他页面动作&#…

linux查看服务器内核CUP版本相关命令

服务器参考 计算架构&#xff1a;x86-64产品系列&#xff1a;华为云耀云服务器操作系列&#xff1a;CentOS 7 执行uname -a查看服务器内核版本 Linux hecs-82210 3.10.0-1160.92.1.el7.x86_64 #1 SMP Tue Jun 20 11:48:01 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux执行hostn…

掌握结构化日志记录:全面指南

在当今复杂的软件生态系统中&#xff0c;应用程序日志非常宝贵。它们允许开发者窥视应用程序的内部&#xff0c;了解系统内部的真实情况。但是&#xff0c;传统的非结构化日志数据有很多不足之处。这些混乱的文本块无法提供完整的画面。要真正发挥日志的力量&#xff0c;我们需…

浅析扩散模型与图像生成【应用篇】(三)——RDDM

3. Residual Denoising Diffusion Models 该文提出一种残差去噪扩散模型&#xff08;RDDM&#xff09;可用去图像生成和图像修复&#xff08;如去除阴影、去雨、暗光提升等&#xff09;。该文最大的特点是提出一种双扩散模型&#xff0c;在扩散过程中不仅包含噪声 ϵ \epsilon …

Windows WMI详解

WMI简介 WMI ( Windows Management Instrumentation, Windows管理规范)是Windows 2000/XP管理系统的核心&#xff0c;属于管理数据和操作的基础模块。设计WMI的初衷是达到一种通用性&#xff0c;通过WM操作系统、应用程序等来管理本地或者远程资源。它支持分布式组件对象模型(…