搜索二维矩阵 II 图解题解
不用全扫,从右上角出发,每步必排一行或一列,O(m+n) 找到答案。
从地图右上角出发:那个角落的数,在它这一行是最大的、在它这一列是最小的。比 target 大就往左走(整列排除),比 target 小就往下走(整行排除)——每一步必然砍掉一整行或一整列,最多走 m+n 步就有结论。
这道题到底在问什么
- matrix
- [[1,4,7,11],[2,5,8,12],[3,6,9,16],[10,13,14,17]]
- target
- 5
- 输出
- true(5 在第 2 行第 2 列)
先想最直接的笨办法
cur 现在指着 5,正好等于 target。直接返回 true。全程只比了 4 次,而暴力要扫 16 格。(动画第 9 步)
最优解:一步一步想明白
- 3最笨的办法是一格一格全看一遍,4×4 要看 16 格,m×n 就是 O(m乘n)。可矩阵明明是排好序的,全扫等于白白浪费了顺序信息。
- 4看右上角那个数:它是所在行里最大的,又是所在列里最小的。这种"一头大一头小"的位置,每比一次都能砍掉一整行或一整列。
- 5cur 站在右上角 (0,3)=11,要找 target=5起点放在右上角:第 0 行第 3 列,值是 11。下面看 11 和 5 谁大。
- 611 大于 5 → 这一整列都比 5 大 → c 减 1,左移到 711 大于 5。因为列是升序的,11 下面的 12、16、17 只会更大,整列都不可能是 5。所以把第 3 列划掉,cur 左移一格到 7。
- 77 大于 5 → 再删一列 → c 减 1,左移到 47 还是大于 5,同样的道理,第 2 列也整列划掉,cur 再左移到 4。注意 cur 一直贴在第 0 行往左挪。
- 84 小于 5 → 这一整行都比 5 小 → r 加 1,下移到 54 小于 5。4 左边的 1 更小,所以第 0 行剩下的都比 5 小,整行划掉。这次方向变了:cur 向下走一格,落在 5。
- 9matrix[1][1] = 5 = target → 找到了,return truecur 现在指着 5,正好等于 target。直接返回 true。全程只比了 4 次,而暴力要扫 16 格。
- 10左、左、下、命中:只往左或往下,从不回头把高亮的几格连起来看:11、7、4、5。cur 要么向左、要么向下,永远不回头。这正是 O(m+n) 的来历——每走一步就少一行或一列。
- 13这就是本题的灵魂:选一个比较结果能二选一排除的起点,让每次比较都把搜索范围缩小一整行或一整列。
- 15(0,0)=1 < 5:往右是 4、往下是 2,两边都更大,没法排除谁如果从左上角 1 开始:1 小于 5,但右边 4 和下面 2 都比 1 大,根本不知道 5 在右边还是下边,没法砍掉任何一边——这就是必须从右上或左下起步的原因。
- 19这套思路的内核是:在有序结构里选一个比较结果能确定唯一排除方向的位置。练熟后可去专题里找同类矩阵 / 双指针题继续迁移,卡住就问小欧或开通关训练。
⚠️ 容易写错的地方
✗ 错:从左上角 (0,0) 开始
✓ 对:从右上角 (0, n-1) 或左下角 (m-1, 0) 开始
左上角是全局最小:比它大时往右还是往下都可能,没法二选一排除,会退化
✗ 错:大于和小于时把左移、下移写反
✓ 对:当前值大于 target 才左移(找更小),小于才下移(找更大)
方向写反会朝着更大的方向跑,越走越离谱,永远找不到
✗ 错:循环条件漏判 c 大于等于 0 或 r 小于行数
✓ 对:r 小于行数 且 c 大于等于 0 两个边界都要守
走出矩阵还继续访问会数组越界;走到界外就说明不存在,该返回 false
完整代码(Python / C++ / Java)
Python
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 FalseC++
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int r = 0, c = (int)matrix[0].size() - 1; // 右上角
while (r < (int)matrix.size() && c >= 0) {
if (matrix[r][c] == target) return true;
else if (matrix[r][c] > target) c--; // 左移
else r++; // 下移
}
return false;
}
};Java
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int r = 0, c = matrix[0].length - 1; // 右上角
while (r < matrix.length && c >= 0) {
if (matrix[r][c] == target) return true;
else if (matrix[r][c] > target) c--; // 左移
else r++; // 下移
}
return false;
}
}套路模板 · 右上角阶梯搜索(挖空骨架)
# 适用:行列均单调的矩阵里查值
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// 行列均单调的矩阵里查值
int r = 0, c = (int)matrix[0].size() - 1; // 右上角起点
while (r < /*行数*/ && c >= /*0*/) {
int v = matrix[r][c];
if (v == target) return true;
else if (v > target) c--; // 太大→左
else r++; // 太小→下
}
return false;// 行列均单调的矩阵里查值
int r = 0, c = matrix[0].length - 1; // 右上角起点
while (r < /*行数*/ && c >= /*0*/) {
int v = matrix[r][c];
if (v == target) return true;
else if (v > target) c--; // 太大→左
else r++; // 太小→下
}
return false;复杂度
时间复杂度
O(m+n)
每比一次都砍掉一行或一列,最多砍 m 行加 n 列,所以至多 m+n 步
空间复杂度
O(1)
只用 r、c 两个下标,不开额外数组
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 搜索二维矩阵 II 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
和 LeetCode 74「搜索二维矩阵 I」有什么区别?+
74 题整个矩阵首尾相接、完全有序,可以拉直成一维数组做二分,O(log(mn));240 只保证各行各列单调、行与行之间不连续,不能整体二分,所以用右上角阶梯 O(m+n)。
能不能对每一行单独做二分?+
可以,每行二分是 O(m·log n),能过。但右上角法 O(m+n) 更优且代码更短,面试更推荐讲后者。
从左下角 (m-1, 0) 出发可以吗?+
完全对称:左下角是本列最大、本行最小。大于 target 就上移 r 减 1,小于就右移 c 加 1,同样 O(m+n)。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。