【Day 12】73.矩阵置零

文章目录

  • 73.矩阵置零
  • 题目:
  • 思路:
    • 方法一:用两个标记数组(易理解,额外空间 O(m+n))
      • 思路(直观)
      • 举例([[1,1,1],[1,0,1],[1,1,1]])
      • 优缺点
      • 代码实现(Go)
    • 方法二:用第一行与第一列做标记(原地,额外空间 O(1))
      • 思路
      • 步骤
      • 代码实现(Go)
  • 总结比较

73.矩阵置零

题目:

给定一个 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]]

示例 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(m+n))

思路(直观)

  1. 新建两个布尔数组 row[m]col[n],初始都为 false
  2. 第一次遍历整个矩阵:如果 matrix[i][j] == 0,就设 row[i] = truecol[j] = true
  3. 第二次遍历整个矩阵:如果 row[i] || col[j]true,就把 matrix[i][j] = 0

举例([[1,1,1],[1,0,1],[1,1,1]])

  • 第一次扫描后:row = [false, true, false]col = [false, true, false]
  • 第二次把第 1 行和第 1 列(索引从 0 开始)按标记置为 0,得到结果 [[1,0,1],[0,0,0],[1,0,1]]

优缺点

  • 优点:实现简单、直观、易于验证。
  • 缺点:额外空间 O(m + n)。

代码实现(Go)

详细注解:

// package main// import "fmt"func setZeroes(matrix [][]int) {m, n := len(matrix), len(matrix[0])// 标记数组(一维布尔数组):记录每一行是否需要置零row := make([]bool, m)// 标记数组(一维布尔数组):记录每一列是否需要置零col := make([]bool, n)// 第一次遍历:找到所有为 0 的位置for i := 0; i < m; i++ {for j := 0; j < n; j++ {if matrix[i][j] == 0 {row[i] = true // 这一行需要清零col[j] = true // 这一列需要清零}}}// 第二次遍历:根据标记数组更新矩阵for i := 0; i < m; i++ {for j := 0; j < n; j++ {if row[i] || col[j] {matrix[i][j] = 0}}}
}// func main() {
// 	m1 := [][]int{{1, 1, 1}, {1, 0, 1}, {1, 1, 1}}
// 	setZeroes(m1)
// 	fmt.Println(m1) // 输出[[1 0 1] [0 0 0] [1 0 1]]
// }

方法二:用第一行与第一列做标记(原地,额外空间 O(1))

思路

rowcol 两个标记数组“挪到”矩阵的第一行和第一列去存储,这样不需要额外数组。但第一行/第一列本身可能一开始就包含 0,若直接当标记使用会丢失它们原本是否含 0 的信息。
因此需要额外两个布尔变量 row0col0 保存第一行和第一列初始是否包含 0。其余步骤和方法一等价(先标记,再根据标记清零),只是标记位置换成了矩阵本身。

步骤

  1. 先扫描第一行,设置 row0 = true 如果第一行含 0。
  2. 先扫描第一列,设置 col0 = true 如果第一列含 0。
    (这两步必须在修改 matrix[0][* ] 或 matrix[*][0] 之前完成,否则会丢信息。)
  3. i=1..m-1, j=1..n-1 扫描:若 matrix[i][j] == 0,则置 matrix[i][0] = 0(标记第 i 行),matrix[0][j] = 0(标记第 j 列)。
  4. 根据第一列的标记清零那些整行(i >= 1)。
  5. 根据第一行的标记清零那些整列(j >= 1)。
  6. 最后根据 row0col0 决定是否把首行/首列全清 0。

注意细节:在第 4、5 步 要跳过第一列/第一行的标记位本身(即从索引 1 开始),防止干扰标记区。最后一步再处理首行/首列。

代码实现(Go)

详细注解:

// package main// import "fmt"func setZeroes(matrix [][]int) {m, n := len(matrix), len(matrix[0])// 两个变量单独记录第一行和第一列是否需要清零row0 := falsecol0 := false// 1) 先检查第一列是否需要清零for i := 0; i < m; i++ {if matrix[i][0] == 0 {col0 = truebreak}}// 2) 再检查第一行是否需要清零for j := 0; j < n; j++ {if matrix[0][j] == 0 {row0 = truebreak}}// 3) 用第一行和第一列作为标记// 从 (1,1) 开始遍历(不动第一行第一列),// 如果 matrix[i][j] == 0,就标记 matrix[i][0] 和 matrix[0][j] 为 0for i := 1; i < m; i++ {for j := 1; j < n; j++ {if matrix[i][j] == 0 {matrix[i][0] = 0 // 标记这一行matrix[0][j] = 0 // 标记这一列}}}// 4) 再次遍历 (1,1) 开始的子矩阵// 逐个遍历矩阵内部元素,根据第一行和第一列的标记,只要行或列被标记,就把该位置置零for i := 1; i < m; i++ {for j := 1; j < n; j++ {if matrix[i][0] == 0 || matrix[0][j] == 0 {matrix[i][j] = 0}}}// 5) 最后处理第一列:如果第一列有 0,就需要把第一列整列置零if col0 {for i := 0; i < m; i++ {matrix[i][0] = 0}}// 以及第一行,如果第一行有 0,就需要把第一行整行置零if row0 {for j := 0; j < n; j++ {matrix[0][j] = 0}}
}// func main() {
// 	m1 := [][]int{{1, 1, 1}, {1, 0, 1}, {1, 1, 1}}
// 	setZeroes(m1)
// 	fmt.Println(m1) // 输出[[1 0 1] [0 0 0] [1 0 1]]
// }

无注释:

// package main// import "fmt"func setZeroes(matrix [][]int) {m, n := len(matrix), len(matrix[0])row0 := falsecol0 := falsefor i := 0; i < m; i++ {if matrix[i][0] == 0 {col0 = truebreak}}for j := 0; j < n; j++ {if matrix[0][j] == 0 {row0 = truebreak}}for i := 1; i < m; i++ {for j := 1; j < n; j++ {if matrix[i][j] == 0 {matrix[i][0] = 0matrix[0][j] = 0}}}for i := 1; i < m; i++ {for j := 1; j < n; j++ {if matrix[i][0] == 0 || matrix[0][j] == 0 {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}}
}// func main() {
// 	m1 := [][]int{{1, 1, 1}, {1, 0, 1}, {1, 1, 1}}
// 	setZeroes(m1)
// 	fmt.Println(m1) // 输出[[1 0 1] [0 0 0] [1 0 1]]
// }

总结比较

特性方法一(标记数组)方法二(首行首列做标记)
额外空间O(m + n)O(1)
实现难度简单稍复杂(要注意首行/首列)
面试倾向如果不限空间,用它写起来安全通常面试官更喜欢 O(1) 的聪明解法(方法二)

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

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

相关文章

Clustering Enabled Wireless Channel Modeling Using Big Data Algorithms

文章目录Clustering TechniquesPartitioning-Based AlgorithmsDensity-Based AlgorithmsHierarchical-based algorithmsClustering Enabled Channel ModelingCluster-Based Channel ModelsClustering AlgorithmsClustering Techniques 聚类是一种已被广泛用于数据分析的技术。…

基于「多模态大模型 + BGE向量检索增强RAG」的儿童绘画心理健康分析系统(vue+flask+AI算法)

一、项目演示视频 基于「多模态大模型 BGE向量检索增强RAG」的儿童绘画心理健康分析系统(vueflaskAI算法)二、技术栈 前端技术栈 (web-vue) 核心框架: Vue 3.5.13 (Composition API) UI组件库: Element Plus 2.9.4 状态管理: Pinia 2.3.1 路由管理: Vue Router 4.5.0 HTTP客户…

QML中的Component

目录 &#x1f9e0; 核心概念&#xff1a;什么是 Component&#xff1f; &#x1f4ca; Component 的两种主要形式 1. 内联 Component&#xff08;在 QML 文件内部定义&#xff09; 2. 外部 Component&#xff08;单独的 .qml 文件&#xff09; &#x1f3af; Component 的…

什么是模型训练中的 特征提取,如何对光伏发电预测中的特征进行提取

&#x1f50d; 什么是模型训练中的“特征提取” 定义&#xff1a;特征提取是从原始数据中提炼出对预测或分类最有用的信息的过程。它的目标是去掉冗余和噪声&#xff0c;保留能最好反映数据规律的特征。 作用&#xff1a; 降低数据维度&#xff0c;减少计算量 提高模型的泛化…

Linux应急响应一般思路(三)

日志分析Linux日志分析Linux日志类型大致可以分为三类&#xff0c;内核和系统日志、用户日志、应用日志内核和系统日志&#xff1a;这种日志主要由syslog管理、根据其配置文件/etc/syslog.conf中的设置决定内核消息和各种系统程序信息记录到哪个位置用户日志&#xff1a;用户日…

【酒店酒水寄存管理效率低?】佳易王酒水寄存管理系统操作教程全解析

前言&#xff1a; &#xff08;一&#xff09;试用版获取方式 资源下载路径&#xff1a;进入博主头像主页第一篇文章末尾&#xff0c;点击卡片按钮&#xff1b;或访问左上角博客主页&#xff0c;通过右侧按钮获取详细资料。 说明&#xff1a;下载文件为压缩包&#xff0c;使用…

Unity 套圈捕捉 UI 实现分享:椭圆环 Shader + 动态进度

Unity 套圈捕捉 UI 实现分享 期望表现效果 《拼贴冒险传 / PatchQuest》 捕捉进度 动态UI实现效果 目标&#xff1a;角色 A 套圈怪物 B&#xff0c;进度环显示围绕角度。技术点&#xff1a;Shader 绘制椭圆环&#xff0c;支持描边、顺/逆时针,需要对两个切口也进行描边。 技术…

MyBatis-Plus代码生成器

MyBatis-Plus 代码生成器是一款高效、灵活的自动化工具,旨在简化 Java 后端开发中的持久层代码编写。通过配置数据库连接和模板参数,它可以一键生成实体类、Mapper 接口、XML 文件、Service 层及 Controller 层代码,大幅提升开发效率,减少重复劳动。 核心优势: 快速生成:…

06-导入Maven项目模块

文章目录1、文章介绍2、模块复制3、导入pom文件4、效果图1、文章介绍 视频定位 2、模块复制 复制资料“02.maven项目”中的两个项目模块到刚刚新建的项目文件路径中 导入后的效果图 3、导入pom文件 4、效果图

Jenkins+docker 微服务实现自动化部署安装和部署过程

Jenkins 是一款流行的开源自动化服务器&#xff0c;广泛用于持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;流程的自动化。通过 Docker 部署 Jenkins 可以简化安装和配置过程&#xff0c;同时保证在不同环境下的一致性。本篇文章将介绍如何使用 Dock…

【芯片后端设计的灵魂:Placement的作用与重要性】

在芯片设计的浩瀚宇宙中&#xff0c;后端物理设计扮演着决定成败的关键角色。其中&#xff0c;​Placement&#xff08;布局&#xff09;​​ 作为整个流程的核心环节&#xff0c;被誉为芯片性能、功耗和面积的“奠基者”。今天&#xff0c;我们就来深入探讨Placement的作用、重…

将FGUI的Shader全部预热后,WebGL平台没有加载成功

1&#xff09;将FGUI的Shader全部预热后&#xff0c;WebGL平台没有加载成功 2&#xff09;iOS如何确认内存扩展使用生效 3&#xff09;SpriteAtlasManager.atlasRequested延后一帧回调 4&#xff09;Unity如何使用Java 17打包 这是第442篇UWA技术知识分享的推送&#xff0c;精选…

Python二进制、八进制与十六进制高级操作指南:从底层处理到工程实践

引言&#xff1a;为何需要掌握进制操作&#xff1f;在现代计算领域&#xff0c;直接操作不同进制的数值是一项核心技术能力。根据2024年Stack Overflow开发者调查报告&#xff1a;73%的低级系统开发涉及位级操作65%的网络协议要求理解十六进制数据80%的硬件接口配置使用二进制控…

离线可用的网络急救方案

在使用电脑的过程中&#xff0c;经常会遇到断网的状况&#xff0c;这种情况让人十分头疼&#xff0c;很多时候我们都不知道去哪里找相关的教程来解决这样的问题。它能一键操作解决电脑的网络故障问题&#xff0c;最关键的是它是完全免费的。它只需解压就可以直接双击使用。把工…

华为云Stack环境中计算资源,存储资源,网络资源发放前的准备工作(中篇)

实验流程说明再上期文章链接如下&#xff1a; 华为云Stack环境中计算资源&#xff0c;存储资源&#xff0c;网络资源发放前的准备工作&#xff08;上篇&#xff09; 华为云Stack环境中计算资源&#xff0c;存储资源&#xff0c;网络资源发放前的准备工作&#xff08;中篇篇&am…

设置密钥连接服务器

要将本地电脑的 SSH 公钥添加到服务器登录&#xff0c;可按以下步骤操作&#xff0c;确保服务器仅允许密钥认证&#xff1a; 一、将本地公钥添加到服务器 &#xff08;前提&#xff1a;你已通过密码或现有方式能登录服务器&#xff0c;且本地已生成 SSH 密钥对&#xff09; 1. …

k8s笔记04-常用部署命令

Kubernetes&#xff08;K8s&#xff09;部署与版本管理命令笔记 一、部署核心命令分类与应用场景 K8s中用于应用部署、版本控制与实例扩缩容的核心命令主要包括三类&#xff0c;分别对应“版本回滚”“手动扩缩容”“自动扩缩容”场景&#xff0c;是CKA考试中部署类题目的核心考…

[系统架构设计师]知识产权(二十)

[系统架构设计师]知识产权&#xff08;二十&#xff09; 一.知识产权的特性 1.特性 无体性&#xff1a;抽象财富 专有性&#xff1a;权利人同意或法律规定外&#xff0c;权利人以外的任何人不得享有或使用该项权力 地域性&#xff1a;只能在该国范围内手法律保护 时间性&#x…

rk3566编译squashfs报错解决

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 编译开源的rk3566代码squashfs报错&#xff0c;tspi_linux_sdk_repo_20240131.tar.gz 下之前先读我 1.tspi_linux_sdk_20230916.tar.gz这个是之前老的没有git和repo的版本&#xff0c;后面会删除掉大家…

HTTP 协议与TCP 的其他机制

TCP 的其他机制TCP头部的标志位SYN&#xff1a;请求建立连接标志位ACK&#xff1a;响应报文标志位PSH&#xff1a;携带数据标志位&#xff0c;通知接收方该从缓冲区读数据FIN&#xff1a;请求断开连接标志位RST&#xff1a;复位标志位URG&#xff1a;紧急数据标志位安全可靠机制…