题目描述
思路解析动画文字版
最笨的办法是一格一格全看一遍,4×4 要看 16 格,m×n 就是 O(m乘n)。可矩阵明明是排好序的,全扫等于白白浪费了顺序信息。
看右上角那个数:它是所在行里最大的,又是所在列里最小的。这种"一头大一头小"的位置,每比一次都能砍掉一整行或一整列。
灵魂帧 1 · 从右上角 11 起步:起点放在右上角:第 0 行第 3 列,值是 11。下面看 11 和 5 谁大。
灵魂帧 2 · 11 > 5,砍掉这一列,左移:11 大于 5。因为列是升序的,11 下面的 12、16、17 只会更大,整列都不可能是 5。所以把第 3 列划掉,cur 左移一格到 7。
灵魂帧 3 · 7 > 5,再砍一列,继续左移:7 还是大于 5,同样的道理,第 2 列也整列划掉,cur 再左移到 4。注意 cur 一直贴在第 0 行往左挪。
灵魂帧 4 · 4 < 5,本行没希望了,下移:4 小于 5。4 左边的 1 更小,所以第 0 行剩下的都比 5 小,整行划掉。这次方向变了:cur 向下走一格,落在 5。
灵魂帧 5 · 5 == 5,命中,返回 true:cur 现在指着 5,正好等于 target。直接返回 true。全程只比了 4 次,而暴力要扫 16 格。
回放 · cur 走出的是一条阶梯折线:把高亮的几格连起来看:11、7、4、5。cur 要么向左、要么向下,永远不回头。这正是 O(m+n) 的来历——每走一步就少一行或一列。
这就是本题的灵魂:选一个比较结果能二选一排除的起点,让每次比较都把搜索范围缩小一整行或一整列。
雷区实演 · 从左上角 1 起步为什么不行:如果从左上角 1 开始:1 小于 5,但右边 4 和下面 2 都比 1 大,根本不知道 5 在右边还是下边,没法砍掉任何一边——这就是必须从右上或左下起步的原因。
面试追问:重点把 240 和 74 的区别讲清楚,再说明右上角和左下角两种对称起点。
迁移阶梯:这套思路的内核是:在有序结构里选一个比较结果能确定唯一排除方向的位置。练熟后可去专题里找同类矩阵 / 双指针题继续迁移,卡住就问小欧或开通关训练。
边界三连:先测空矩阵,再测 1×1,最后测一个根本不在表里的数,确认会一路走到边界外干净地返回 false。
参考代码
class Solution: def searchMatrix(self, matrix, target): r, c = 0, len(matrix[0]) - 1 # 起点:右上角 while r < len(matrix) and c >= 0: if matrix[r][c] == target: return True elif matrix[r][c] > target: c -= 1 # 太大,左移砍一列 else: r += 1 # 太小,下移砍一行 return False复杂度
- 时间复杂度:O(m+n),每比一次都砍掉一行或一列,最多砍 m 行加 n 列,所以至多 m+n 步
- 空间复杂度:O(1),只用 r、c 两个下标,不开额外数组
可套用的代码模板
填空时盯三处:起点选能排除的角、循环守住两条边界、大于左移小于下移。把这三处想清楚,这类题就成模板了。
# 适用:行列均单调的矩阵里查值r, c = 0, len(matrix[0]) - 1 # ← 起点必须是能二选一排除的角while r < ____ and c >= ____: # ← 守住两条边界 v = matrix[r][c] if v == target: return True elif v > target: c -= 1 # ← 太大,砍掉当前列 else: r += 1 # ← 太小,砍掉当前行return False易错点
面试追问把动画讲成自己的话
追问和 LeetCode 74「搜索二维矩阵 I」有什么区别?
追问能不能对每一行单独做二分?
追问从左下角 (m-1, 0) 出发可以吗?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
下一个排列
LeetCode 31 · 中等 · 沿着 数组 & 哈希 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题