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

一天一道算法题(9):空间优化从O(mn)到O(1)的思路与实现解析

矩阵置零(LeetCode 73题)三种解法详解

文章目录

  • 矩阵置零(LeetCode 73题)三种解法详解
    • 题目描述
    • 思路分析
      • 难点所在
      • 解法一:O(mn) 空间(最直观)
      • 解法二:O(m+n) 空间(改进)
      • 解法三:O(1) 空间(最优解)
    • 总结对比

题目描述

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

思路分析

难点所在

在遍历矩阵的过程中,如果将遇到的0所在行和列直接变为0,那么后续遍历时,我们无法分辨某个位置的0是原本就有的,还是被我们修改出来的。这会导致错误传播,将原本不该清零的位置也清零了。

解法一:O(mn) 空间(最直观)

最直接的想法是复制一个完全相同的矩阵,然后遍历原矩阵,遇到0就在复制的矩阵中清空对应的行和列。这样我们始终基于原始状态进行操作,避免了错误传播。

funcsetZeroes(matrix[][]int){// 复制矩阵temp:=make([][]int,len(matrix))fori:=0;i<len(matrix);i++{temp[i]=append([]int(nil),matrix[i]...)}// 遍历复制的矩阵,在原矩阵上修改fori:=0;i<len(temp);i++{forj:=0;j<len(temp[i]);j++{iftemp[i][j]==0{// 清空当前行clear(matrix[i])// 清空当前列fork:=0;k<len(matrix);k++{matrix[k][j]=0}}}}}

复杂度分析:

  • 时间复杂度:O(mn),需要遍历矩阵两次
  • 空间复杂度:O(mn),复制了一个完整的矩阵

这种方法虽然直观,但不符合题目对原地算法的要求

解法二:O(m+n) 空间(改进)

仔细观察,我们其实不需要复制整个矩阵。只需要记录哪些行哪些列需要清零即可。用两个布尔数组分别标记:

  • row[i] = true表示第 i 行需要清零
  • col[j] = true表示第 j 列需要清零
funcsetZeroes(matrix[][]int){// 行标记数组row:=make([]bool,len(matrix))// 列标记数组col:=make([]bool,len(matrix[0]))// 第一次遍历:标记需要清零的行和列fori:=0;i<len(matrix);i++{forj:=0;j<len(matrix[0]);j++{ifmatrix[i][j]==0{row[i]=truecol[j]=true}}}// 第二次遍历:根据标记清零fori:=0;i<len(matrix);i++{forj:=0;j<len(matrix[0]);j++{ifrow[i]||col[j]{matrix[i][j]=0}}}}

复杂度分析:

  • 时间复杂度:O(mn)
  • 空间复杂度:O(m+n)

这种方法比解法一好很多,但仍然不是最优解

解法三:O(1) 空间(最优解)

能否只使用常量空间?答案是肯定的!

核心思想:利用矩阵的第一行第一列作为标记数组。

  • matrix[0][j]标记第 j 列是否需要清零
  • matrix[i][0]标记第 i 行是否需要清零

但这里有个问题:matrix[0][0]既属于第一行又属于第一列,会产生冲突。解决方案是用两个独立变量row1col1分别记录第一行和第一列本身是否包含 0。

funcsetZeroes(matrix[][]int){// 用两个变量记录第一行、第一列是否存在 0row1,col1:=1,1// 检查第一行是否有 0forj:=0;j<len(matrix[0]);j++{ifmatrix[0][j]==0{row1=0break}}// 检查第一列是否有 0fori:=0;i<len(matrix);i++{ifmatrix[i][0]==0{col1=0break}}// 遍历除第一行第一列外的所有元素fori:=1;i<len(matrix);i++{forj:=1;j<len(matrix[0]);j++{ifmatrix[i][j]==0{// 用第一行标记列matrix[0][j]=0// 用第一列标记行matrix[i][0]=0}}}// 根据标记清零(除第一行第一列外)fori:=1;i<len(matrix);i++{forj:=1;j<len(matrix[0]);j++{ifmatrix[i][0]==0||matrix[0][j]==0{matrix[i][j]=0}}}// 最后处理第一行ifrow1==0{forj:=0;j<len(matrix[0]);j++{matrix[0][j]=0}}// 最后处理第一列ifcol1==0{fori:=0;i<len(matrix);i++{matrix[i][0]=0}}}

复杂度分析:

  • 时间复杂度:O(mn)
  • 空间复杂度:O(1)

注意事项:

  1. 必须先处理除第一行第一列外的元素,最后再处理第一行和第一列
  2. 如果一开始就清零第一行或第一列,会破坏标记信息

总结对比

解法空间复杂度特点
复制矩阵O(mn)最直观,但不符合题目要求
标记数组O(m+n)简单改进,但非最优
第一行第一列标记O(1)最优解,面试首选

这道题的核心在于如何用有限的额外空间记录行和列的清零信息。从 O(mn) 到 O(m+n) 再到 O(1),每一步优化都体现了空间换时间的思想转变,值得细细品味。

http://www.jsqmd.com/news/1387319/

相关文章:

  • 2026年合肥市瑶海区GEO服务商代理加盟本地靠谱推荐:创业者选型指南与避坑全攻略 - 科技快讯
  • 深度解析:长沙大型网站建设公司如何选择靠谱团队打造企业数字化核心竞争力
  • 迈克“智汇”实验室全解析:从检验数据工厂到智能决策中心 - 品牌产品观察推荐官
  • 管理=管人+管事(项目管理=PMP认证考试+软考认证考试+信创认证考试+MBA论文)--入栏需看
  • 视频转AVI后文件巨大?2026免费工具手把手教学,保姆级教程选对MJPG/DV编码 - 时时资讯
  • Windows也能享受苹果字体?PingFangSC字体包让你的设计跨越平台鸿沟
  • PDF补丁丁:免费开源工具终极指南,轻松搞定PDF编辑难题
  • 3分钟配置LX Music音源:解锁全网无损音乐的终极免费方案
  • 2026杭州淳安县楼顶漏水避坑指南,本地老牌公司,质保可查 - 专业防水施工
  • 揭秘网站建设推广人员如何在互联网红海中杀出一条血路并实现价值最大化
  • 2026年|温州乐清GEO服务商代理加盟怎么选?本地靠谱推荐与城市合伙人模式解析 - 企业新闻快传
  • 如何快速搭建国标视频监控平台:企业级视频管理完整指南
  • 解决K8s网络复杂性:network-mapper助力微服务通信可观测性与安全合规
  • 失眠人群树洞哄睡音频平台深度测评|2026树洞故事哄睡,隐私安全优先,完整对比旧纸树洞、徘徊树洞、同频树洞,附陪玩渠道指南 - 时时资讯
  • 2026年合肥庐阳区GEO服务商代理加盟怎么选?本地靠谱服务商推荐 - 小随科技
  • K12机构想被家长在AI里找到?GEO优化服务商这样选 - 品牌前沿专家
  • AI Agent在企业级应用中的发展趋势:从工具性创新到结构性转型
  • 深度解析:如何高效使用IP-Adapter-FaceID实现精准人脸保持生成
  • 2026杭州建德市楼顶漏水避坑指南,本地老牌公司,质保可查 - 专业防水施工
  • 3分钟搞定!免费解锁全网无损音乐的洛雪音乐音源配置指南
  • 如何永久保存微信聊天记录?WeChatMsg免费导出完整指南
  • 终极Windows防撤回指南:RevokeMsgPatcher技术解析与实战应用
  • 一文读懂Scylla-Rust-Driver重试机制:从默认策略到降级一致性配置
  • 霍尔闭环电流传感器在电动观光旅游车上的应用
  • Route与PSR标准:如何确保你的应用符合行业规范
  • 原创图片频繁被盗用?2026两款免费工具教程!倾斜平铺水印,让盗图者难以清除 - 时时资讯
  • 2026年长沙GEO服务商推荐:长沙丹翼咨询有限公司强调信源驱动与持续复测 - 生活动态圈
  • 别只盯着排名看,领导力亚太EMBA我跑了6场宣讲会
  • 2026年|温州龙港市GEO服务商代理加盟怎么选?本地靠谱推荐与避坑指南 - 子柔传媒
  • THK选型手册详解