题目描述
编写一个高效的算法来搜索mxn矩阵中的一个目标值,该矩阵具有以下特性:
- 每行升序排列。
- 每列升序排列。
示例1:
输入:
matrix = [
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
], target = 5
输出:true
示例2:
输入:
matrix = [
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
], target = 20
输出:false
思路
本题可以采用二分查找算法来求解。由于矩阵每行都是升序排列的,每列也是升序排列的,因此我们可以先在第一列中进行二分查找。如果找到了目标值,则直接返回true;否则,我们可以在目标值可能存在的行中进行二分查找,最后判断目标值是否存在即可。
先在第一列二分查找原因:找到第一个大于等于目标值的元素所在行,然后在该行进行线性搜索。这样可以避免很多不必要的搜索,提高算法效率。
代码实现
function searchMatrix(matrix: number[][], target: number): boolean {
const m = matrix.length;
if (m === 0) {
return false;
}
const n = matrix[0].length;
let left = 0,
right = m - 1;
// 在第一列中进行二分查找
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (matrix[mid][0] === target) {
return true;
} else if (matrix[mid][0] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
// 在目标值可能存在的行中进行二分查找
for (let i = 0; i < left; i++) {
let l = 0,
r = n - 1;
while (l <= r) {
const mid = Math.floor((l + r) / 2);
if (matrix[i][mid] === target) {
return true;
} else if (matrix[i][mid] > target) {
r = mid - 1;
} else {
l = mid + 1;
}
}
}
// 未找到目标值
return false;
}
复杂度分析
-
时间复杂度为 ,其中 和 分别为矩阵的行数和列数。因为需要在第一列中进行一次二分查找,时间复杂度为 ;每列中进行最多一次二分查找,总时间复杂度为 。
-
空间复杂度为 ,因为只使用了常数个额外变量。