文章目录
📖 题目简述
给定一个
m x n的二维矩阵,其中每一行的整数从左到右按升序排列,每一行的第一个整数都比前一行的最后一个整数大。
请编写一个高效算法,判断给定的目标值是否存在于矩阵中。
一、题目理解与特征分析
该二维矩阵在形式上可以视为一个"升序的一维数组":
[
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 60]
]
如果将整个矩阵展开为一维序列:
[1, 3, 5, 7, 10, 11, 16, 20, 23, 30, 34, 60]
可以看到它实际上是一个从小到大的严格递增序列。
因此,我们可以利用二分查找思想在该"虚拟一维数组"中查找目标值。
二、解法总览
搜索二维矩阵
一维化二分查找
原理: 将二维矩阵视作一维递增数组
优点: 简洁高效, 时间复杂度O(log(m*n))
实现: 二分定位行列索引转换
行列方向双指针搜索
原理: 从右上角或左下角开始向目标逼近
优点: 思路直观,无需索引映射
实现: 根据大小移动行或列指针
暴力遍历
原理: 线性扫描所有元素
缺点: 时间复杂度高 O(m*n)
三、方法一:一维化二分查找(推荐)
原理说明
由于矩阵中的每行和每列都有严格的有序关系,可以将整个矩阵看成一个长度为 m * n 的一维递增数组,对其使用二分查找。
索引映射方式如下:
- 行索引:
row = mid / n - 列索引:
col = mid % n
算法流程
否
是
相等
小于
大于
开始
初始化 left=0, right=m*n-1
left <= right?
返回false
计算 mid=(left+right)/2
计算 row=mid/n, col=mid%n
比较 matrix[row][col] 与 target
返回true
left = mid + 1
right = mid - 1
结束
Java代码实现
java
public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int left = 0, right = m * n - 1;
while (left <= right) {
int mid = (left + right) / 2;
int row = mid / n;
int col = mid % n;
int value = matrix[row][col];
if (value == target) {
return true;
} else if (value < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return false;
}
}
时间复杂度分析
- 时间复杂度 :
O(log(m * n)) - 空间复杂度 :
O(1)
四、方法二:从右上角开始的双指针法
原理
- 从右上角元素开始(即第 0 行的最后一列)。
- 如果当前元素大于目标值,则向左移动(列减1)。
- 如果当前元素小于目标值,则向下移动(行加1)。
- 如果相等则返回
true。
动态过程示意图
Target Pointer Matrix Target Pointer Matrix alt [当前值 > 目标] [当前值 < 目标] [相等] 选中右上角元素 比较当前值 向左移动 (col--) 向下移动 (row++) 返回true
Java代码实现
java
public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int row = 0, col = n - 1;
while (row < m && col >= 0) {
int value = matrix[row][col];
if (value == target) return true;
else if (value > target) col--;
else row++;
}
return false;
}
}
时间复杂度分析
- 时间复杂度 :
O(m + n) - 空间复杂度 :
O(1)
五、方法三:暴力法(仅作对比)
原理
- 遍历矩阵中的每个元素,逐一与目标值比较。
虽然能解决问题,但时间效率低。
Java实现
java
public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == target) return true;
}
}
return false;
}
}
时间复杂度分析
- 时间复杂度 :
O(m * n) - 空间复杂度 :
O(1)
六、思维框架总结
搜索二维矩阵思维框架
数据结构特性
行内升序
行间连续增大
解法思路
二分查找
映射为一维数组
双指针逼近
从右上角移动
线性遍历
暴力检测
复杂度对比
log m*n
m+n
m*n
七、结论与优化建议
- 若矩阵规模较大且行列均递增,二分查找法是最优选择;
- 对于需要实时搜索或数据不断更新的场景,可考虑双指针法;
- 暴力法仅作为教学比对使用。