74. 搜索二维矩阵

中等 含交互动画

学完这道你应该能: 说清它为什么用「矩阵」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

矩阵每行从左到右升序,且每行第一个数都大于上一行最后一个数。判断 target 在不在矩阵里,在返回 true,否则 false。

matrix = [[1,3,5,7],[10,11,16,20]]
target = 3
输出 = true(3 在第 0 行第 1 列)

思路解析

挨个看每个格子当然能找到,可这把「整体有序」这个大礼包完全浪费了。题目都把有序明牌摆你面前了,必须把二分用起来。

转折:既然拉直就是升序数组,那就对下标 0..m·n−1 这条「虚拟数组」直接二分。要取第 mid 个数时,行号 = mid // n、列号 = mid % n(n 是列数)。这样根本不用真把矩阵拼起来,O(1) 就能换算回原矩阵取值。

准备 · 拉直成升序数组:把矩阵拉直就是这条数组。l=0、r=7,范围是全部 8 个数。要找 target = 3,全程不真拼数组,靠 mid//n、mid%n 回原矩阵取值。

第 1 轮 · 取 mid:中点 mid = (0+7)//2 = 3。换算回矩阵:行 = 3//4 = 0、列 = 3%4 = 3,取到 matrix[0][3] = 7。拿它和 target = 3 比。

第 1 轮 · 判断收缩:7 比 3 大,目标在左半边。把 r 收到 mid−1 = 2,右边那半(含 7,灰)整个丢掉。范围缩到 [0, 2]。

第 2 轮 · 取 mid:现在范围是 [0, 2]。新中点 mid = (0+2)//2 = 1,换算:行 = 1//4 = 0、列 = 1%4 = 1,取到 matrix[0][1] = 3

第 2 轮 · 命中!:matrix[0][1] 正好等于 3!返回 true。全程只看了 2 个数,靠的就是 mid//n、mid%n 这一步换算。

再看个找不到的 · target=4:换个例子:找 4。数组里没有 4,看二分怎么靠 l 越过 r 收尾。

4 · mid=3 → 7 大于 4:mid=3 取到 7,比 4 大,r 收到 2。范围 [0, 2]。

4 · mid=1 → 3 小于 4:mid=1 取到 3,比 4 小,l 收到 2。现在 l 和 r 都指向 2。

4 · mid=2 → 5 大于 4,l 越过 r:mid=2 取到 5,比 4 大,r 收到 1。这时 l(2) 越过了 r(1),范围空了,循环结束,返回 false

看到「每行升序 + 行间衔接」,就把二维拉直当一维,用 mid // n 和 mid % n 来回换算下标,剩下交给二分。这是把高维问题压成一维有序的经典技巧。

参考代码(Python)

Python
1def searchMatrix(matrix, target):
2    m, n = len(matrix), len(matrix[0])
3    l, r = 0, m * n - 1                  # 虚拟数组下标 [0, m·n−1]
4    while l <= r:                        # 找具体值,闭区间带等号
5        mid = (l + r) // 2
6        v = matrix[mid // n][mid % n]    # 一维下标还原行列,n 是列数
7        if v == target: return True
8        elif v < target: l = mid + 1     # 偏小,丢左半
9        else: r = mid - 1                # 偏大,丢右半
10    return False

复杂度分析

  • 时间复杂度:O(log(m·n)) —— 在 m·n 个数上二分,每轮砍一半
  • 空间复杂度:O(1) —— 只用 l、r、mid 几个变量,不真拼数组

套路模板

记牢换算公式:行 = mid // n、列 = mid % n,n 是列数。这是全题唯一的坎,背下来普通二分就能解二维。

Python
1l, r = 0, m * n - 1
2while l <= r:
3    mid = (l + r) // 2
4    v = matrix[mid // n][mid % n]      # 行 = mid//n,列 = mid%n
5    if v == target: return True
6    elif v < target: l = mid + 1
7    else: r = mid - 1
8return False

易错点

  • 错误写法:mid // m、mid % m(拿行数 m 换算)正确写法:mid // n、mid % n(拿列数 n 换算)(拉直是按行铺的,每行有 n 个数,所以除、模都用列数 n;用行数 m 会算出完全错的格子)
  • 错误写法:r = m * n(越界)正确写法:r = m * n − 1(一共 m×n 个数,最大下标是 m×n−1,写成 m·n 会越界访问)
  • 错误写法:while l < r(漏等号)正确写法:while l <= r(这题找的是具体值、不是边界,区间缩到只剩一个数时还得比一次,漏等号会漏判最后一个数)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →162. 寻找峰值 ← 返回题库