题目简述
二维矩阵满足:
-
每一行从左到右递增
-
每一行首元素大于上一行最后一个元素
这意味着矩阵整体呈现严格递增的一维序列。
例如:
cpp
[
[1, 3, 5, 7],
[10,11,16,20],
[23,30,34,60]
]
可以视为:
cpp
1,3,5,7,10,11,16,20,23,30,34,60
核心思想:二维转一维
二维矩阵按行拼接,即坐标映射:
cpp
i → (i / n, i % n)
其中:
-
n是列数 -
i / n是行号 -
i % n是列号
二分查找代码(闭区间写法)
cpp
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size();
int n = matrix[0].size();
int left = 0;
int right = m * n - 1; // 一维区间 [0, m*n-1]
while (left <= right) {
int mid = left + (right - left) / 2;
// mid / n → 行
// mid % n → 列
if (matrix[mid / n][mid % n] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
// 💥 关键:避免越界访问 matrix[left]
if (left == m * n) return false;
return matrix[left / n][left % n] == target;
}
};
重点:闭区间二分为什么会越界?
闭区间写法:
cpp
left = 0
right = size-1
while (left <= right)
这一写法的返回值有一个特点:
最终的 left 可能等于 size
这是完全符合设计的,因为:
-
如果所有元素都小于 target
⇒ 返回应该是第一个大于等于 target 的位置
⇒ 也就是 size
⇒ left == size
但问题来了:
你一旦直接访问:
cpp
nums[left]
若 left == size:
cpp
nums[size] // 非法访问,越界 ❌
如何避免越界?
只要使用闭区间写法,就必须判断:
cpp
if (left == size) return ...
总结
闭区间写法凡是涉及到访问nums[size]一定要注意边界访问越界问题。
二维搜索矩阵的核心:
-
把矩阵视为一维递增数组
-
用
mid / n、mid % n完成坐标映射
闭区间写法最大的坑:
最终 left 可能等于数组长度(size),访问会越界
所以必须判断:
cpp
if (left == size) return ...;
为什么需要判断?
- 因为
left = size是合法返回值,但不是合法下标