题目描述
思路解析动画文字版
核心一句话:用第一行第一列当标记位记录哪些行列要清零,再统一置零,省下额外空间。
阶段①:第一行、第一列马上要被拿来当「草稿纸」记标记,所以先单独记住它们本来含不含 0。本例里 firstRowZero=false、firstColZero=false(都不含,待会儿不用额外清它们自己)。
阶段②:扫到 matrix[1][1]=0(红色)。先别急着清,去它的行首 (1,0) 和列首 (0,1) 各打个 0 当标记,记住「第 1 行、第 1 列都要清」。
把行首 matrix[1][0] 置 0 当标记(浅橘)——表示第 1 行整行待清。
把列首 matrix[0][1] 置 0 当标记(浅橘)——表示第 1 列整列待清。这个 0 本身的「清行清列」任务,就交给这两个标记记着了。
阶段②:扫到 matrix[3][2]=0(红色)。先别急着清,去它的行首 (3,0) 和列首 (0,2) 各打个 0 当标记,记住「第 3 行、第 2 列都要清」。
把行首 matrix[3][0] 置 0 当标记(浅橘)——表示第 3 行整行待清。
把列首 matrix[0][2] 置 0 当标记(浅橘)——表示第 2 列整列待清。这个 0 本身的「清行清列」任务,就交给这两个标记记着了。
阶段②扫描完毕。内部所有 0 都已经在它们的行首、列首留下了标记(浅橘共 4 个)。下面按标记统一清零。
(1,1) 行首(1,0)、列首(0,1) 都标了 → 该清。它本来就是 0,标记落定为「已处理」(绿色)。
(1,2)=7 → 查它的行首/列首:行首(1,0)、列首(0,2) 都标了 → 这一格要清零。
(1,2) 置 0 完成(绿色)。
(1,3)=8 → 查它的行首/列首:行首(1,0) 标了 → 这一格要清零。
(1,3) 置 0 完成(绿色)。
(2,1)=10 → 查它的行首/列首:列首(0,1) 标了 → 这一格要清零。
(2,1) 置 0 完成(绿色)。
(2,2)=11 → 查它的行首/列首:列首(0,2) 标了 → 这一格要清零。
(2,2) 置 0 完成(绿色)。
(3,1)=14 → 查它的行首/列首:行首(3,0)、列首(0,1) 都标了 → 这一格要清零。
(3,1) 置 0 完成(绿色)。
(3,2) 行首(3,0)、列首(0,2) 都标了 → 该清。它本来就是 0,标记落定为「已处理」(绿色)。
(3,3)=16 → 查它的行首/列首:行首(3,0) 标了 → 这一格要清零。
(3,3) 置 0 完成(绿色)。
阶段④:firstRowZero=false → 第一行本来就没有 0,不用额外清它(它上面的标记 0 是「列待清」的记号,但本例第一行没真正落到要清的列上的值,保持)。
firstColZero=false → 第一列本来没有 0,不用额外清它自己。至此全部处理完毕。
最终结果:所有该清的行列都已清零。原来在 (1,1)、(3,2) 的两个 0,把第 1、3 行和第 1、2 列都拉成了 0。
只要 0 落在第一行/第一列,就全靠那两个布尔变量把它们的命运记住。
面试要点:标记与清零必须两阶段分离;O(1) 的本质是把标记数组折叠进矩阵自身。
参考代码
def setZeroes(matrix): m, n = len(matrix), len(matrix[0]) first_row = any(matrix[0][j] == 0 for j in range(n)) first_col = any(matrix[i][0] == 0 for i in range(m)) for i in range(1, m): # ② 内部扫描打标记 for j in range(1, n): if matrix[i][j] == 0: matrix[i][0] = 0 # 行首标记 matrix[0][j] = 0 # 列首标记 for i in range(1, m): # ③ 按标记清零 for j in range(1, n): if matrix[i][0] == 0 or matrix[0][j] == 0: matrix[i][j] = 0 if first_row: # ④ 收尾第一行/列 for j in range(n): matrix[0][j] = 0 if first_col: for i in range(m): matrix[i][0] = 0复杂度
- 时间:O(m·n),每个格子最多被访问常数次(扫描 + 清零两遍)
- 空间:O(1),只用 firstRow / firstCol 两个布尔量,标记借矩阵自身的首行首列
易错点
面试追问把动画讲成自己的话
追问O(m+n) 的写法和这个 O(1) 写法差在哪?
追问为什么不能简单地「遇到 0 就把整行整列清了」?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
快乐数
LeetCode 202 · 简单 · 沿着 数学 & 几何 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题