本文概览:本文讲解搜索二维矩阵的核心思路:利用矩阵完全递增的性质,通过两次二分查找快速定位目标值
一、题目

二、题目分析
这题的矩阵有一个关键性质:完全递增。
- 每行从左到右递增
- 下一行所有的数都比上一行大
- 按照"一行一行从左到右"的顺序遍历,所有数字是递增的
比如这个矩阵:
1 3 5 7
10 11 16 20
23 30 34 60
展开后就是 [1, 3, 5, 7, 10, 11, 16, 20, 23, 30, 34, 60],完全递增。
基于这个性质,我们可以采取两次二分查找的方法快速找到目标值:
- 第一次二分:确定 target 在哪一行
- 第二次二分:在确定的行内查找 target
思路概览
Java 实现代码如下
java
public boolean searchMatrix(int[][] matrix, int target) {
int height = matrix.length;
int width = matrix[0].length;
int row;
int bottom = 0;
int top = height - 1;
while(bottom <= top) {
int mid = bottom + (top - bottom) / 2;
// 目标在当前行
if(matrix[mid][0] <= target && matrix[mid][width - 1] >= target) {
row = mid;
// 目标在当前行, 二分查找
int left = 0;
int right = width - 1;
while(left <= right) {
int col = left + (right - left) / 2;
if(matrix[row][col] == target) {
return true;
} else if(matrix[row][col] > target) {
right = col - 1;
} else {
left = col + 1;
}
}
return false;
}
// 目标在当前行之前
else if(matrix[mid][0] > target) {
top = mid - 1;
}
// 目标在当前行之后
else if(matrix[mid][width - 1] < target) {
bottom = mid + 1;
}
}
return false;
}
思路简要说明:
- 第一次二分 :对行进行二分,判断 target 是否在当前行的范围内(
>= 第一个元素且<= 最后一个元素) - 第二次二分:在确定的行内,用标准的二分查找找 target
- 时间复杂度:O(log m + log n),m 是行数,n 是列数
三、思路详解
第一步:矩阵的关键性质
矩阵的关键性质是完全递增。这意味着:
- 每行的第一个元素是这一行的最小值
- 每行的最后一个元素是这一行的最大值
- 第 i 行的所有元素都小于第 i+1 行的所有元素
所以我们可以用每行的首尾元素来判断 target 是否在这一行:
matrix[mid][0] <= target && matrix[mid][width-1] >= target
第二步:第一次二分------确定行
对行进行二分查找,每次取中间行 mid,判断 target 是否在这一行的范围内:
matrix[mid][0] <= target && matrix[mid][width-1] >= target:target 在这一行,进入第二次二分matrix[mid][0] > target:target 在这一行之前(上面的行),更新top = mid - 1matrix[mid][width-1] < target:target 在这一行之后(下面的行),更新bottom = mid + 1
第三步:第二次二分------确定列
确定了行 row 之后,在这一行内用标准的二分查找找 target:
left = 0,right = width - 1mid = left + (right - left) / 2matrix[row][mid] == target:找到,返回 truematrix[row][mid] > target:target 在左边,right = mid - 1matrix[row][mid] < target:target 在右边,left = mid + 1
第四步:完整执行过程
以这个矩阵为例,target = 11:
1 3 5 7
10 11 16 20
23 30 34 60
第一次二分:确定行
初始:bottom=0, top=2
第 1 轮:
mid = 0 + (2-0)/2 = 1
matrix[1][0] = 10, matrix[1][3] = 20
10 <= 11 && 11 <= 20 → target 在第 1 行 ✓
进入第二次二分
第二次二分:确定列
初始:left=0, right=3
第 1 轮:
col = 0 + (3-0)/2 = 1
matrix[1][1] = 11 == 11 → 找到!返回 true ✓
再举一个找不到的例子,target = 13:
第一次二分:确定行
初始:bottom=0, top=2
第 1 轮:
mid = 1
matrix[1][0] = 10, matrix[1][3] = 20
10 <= 13 && 13 <= 20 → target 在第 1 行 ✓
进入第二次二分
第二次二分:确定列
初始:left=0, right=3
第 1 轮:
col = 1, matrix[1][1] = 11 < 13
left = 2
第 2 轮:
left=2, right=3
col = 2, matrix[1][2] = 16 > 13
right = 1
第 3 轮:
left=2, right=1
left > right,退出循环
返回 false
第五步:时间复杂度分析
- 第一次二分:对行进行二分,时间复杂度 O(log m),m 是行数
- 第二次二分:对列进行二分,时间复杂度 O(log n),n 是列数
- 总时间复杂度:O(log m + log n)
如果直接遍历整个矩阵,时间复杂度是 O(m × n)。二分查找的优势非常明显。
四、总结
搜索二维矩阵的核心是利用矩阵完全递增的性质,通过两次二分查找快速定位目标值:
- 第一次二分:确定 target 在哪一行(用每行的首尾元素判断范围)
- 第二次二分:在确定的行内查找 target
这个思路可以推广到所有"有序矩阵查找"类题目。