杨氏矩阵查找应从右上角或左下角开始,因仅这两点能每次比较排除整行或整列;推荐右上角,初始化row=0、col=n-1,若相等返回true,大于target则col--,小于则row++,时间复杂度o(m+n)。

杨氏矩阵的结构特点决定查找策略
杨氏矩阵不是普通二维数组,它要求每行从左到右递增、每列从上到下递增。这种双单调性让 std::lower_bound 或暴力遍历都失效——你不能对某一行二分后直接跳过其他行,也不能对某一列二分后忽略行间关系。
真正能利用结构特性的起点只有两个角:右上角或左下角。选右上角最直观,因为它的右边无元素、上边无元素,每次比较都能确定排除一整行或一整列。
从右上角出发的 O(m+n) 查找实现
设矩阵为 matrix,维度为 m 行 n 列,目标值为 target。初始化 row = 0、col = n - 1,然后循环:
- 若
matrix[row][col] == target,找到,返回true - 若
matrix[row][col] > target,说明该列所有下方元素都更大,col-- - 若
matrix[row][col] ,说明该行所有左侧元素都更小,<code>row++ - 越界(
row >= m或col )即未找到
这个过程最多走 m + n - 1 步,时间复杂度稳定在线性级别,比对每行调用 std::lower_bound 的 O(m log n) 更优,尤其当矩阵扁长时。
容易踩的边界坑:空矩阵和越界检查
常见错误是忽略输入校验,直接访问 matrix[0][n-1] 导致段错误。必须先确认:
-
matrix非空,且!matrix.empty() -
matrix[0]非空,即!matrix[0].empty() - 否则
n为 0,col = n - 1会变成极大正数(无符号溢出)或负数(有符号),引发未定义行为
安全写法是把维度提取写成:int m = matrix.size(); int n = m ? matrix[0].size() : 0;,再判断 m == 0 || n == 0 就直接返回 false。
为什么不用二分查找整个矩阵?
有人尝试把二维数组展平成一维再二分,这在杨氏矩阵中不可行——展平后的序列不是有序的。例如:
1 4 7 2 5 8 3 6 9
按行展平是 [1,4,7,2,5,8,3,6,9],显然不单调。强行排序再二分就破坏了原结构,也失去 O(m+n) 的优势。杨氏矩阵的“有序”是二维偏序,不是全序,这点必须认清。
右上角法看似简单,但每步排除的是一整行或一整列,这是它高效的根本;漏掉任意一个越界分支,或者误把杨氏矩阵当成普通有序二维表来处理,都会让逻辑崩坏。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











