# 搜索二维矩阵(74)
# 题目
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。 每行的第一个整数大于前一行的最后一个整数。
# 示例
输入:
matrix = [
[1, 3, 5, 7],
[10,11,16,20],
[23,30,34,60]
]
target = 3
1
2
3
4
5
6
2
3
4
5
6
输出:true
输入:
matrix = [
[1, 3, 5, 7],
[10,11,16,20],
[23,30,34,60]
]
target = 13
1
2
3
4
5
6
2
3
4
5
6
输出:false
# 提示
- m == matrix.length
- n == matrix[i].length
- 1 <= m, n <= 100
- -104 <= matrix[i][j], target <= 104
# 算法
# 双重遍历
const searchMatrix = (matrix, target) => {
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] === target) return true;
}
}
return false;
};
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 定位查找
- 如果target小于行末尾元素,那么target可能在这一行
- 如果target大于行内某元素,那么target可能在这个元素左侧
我们从右上角开始先定位行,再在行内向左顺次查找target
我们的结束条件是遍历的行数row
大于最大行数或者行内的列数column
小于0
const searchMatrix = (matrix, target) => {
let row = 0,
column = matrix[0].length - 1;
while (row < matrix.length && column > 0) {
if (target > matrix[row][column]) row++;
else if (target > matrix[row][column]) column--;
else return true;
}
return false;
};
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 行内二分查找
我们注意到题目中的“递增”条件,想到使用“二分查找”来解题
我们先根据行尾元素来判断target在哪一行,然后因为行内元素递增,所以我们可以使用二分查找在行内查找是否存在对应元素
const searchMatrix = (matrix, target) => {
let row = 0,
column = matrix[0].length - 1;
while (row < matrix.length && target > matrix[row][column]) row++;
if (row >= matrix.length) return false;
let start = 0,
end = column;
while (start <= end) {
let m = ~~((start + end) / 2);
if (matrix[row][m] === target) return true;
else if (matrix[row][m] > target) end = m - 1;
else if (matrix[row][m] < target) start = m + 1;
}
return false;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 二分查找
上面的方法我们还可以进行优化:
我们将矩阵的每一行拼接成一个数组,这个数组下标范围是[0, matrix.length * matrix[0].length - 1]
,从题目的已知可知整个数组是递增的,我们就可以使用二分查找
来检索数据
数组下标的范围就是二分查找的起点和终点,然后我们就可以算出数组中间的那个元素进而进行判断,关键在于我们将数组中第~~(start+end)/2
个元素对应到矩阵中——我们将中间的坐标值设为mid
,那么对应到矩阵中,这个元素的就在第~~(mid/column)
行、第~~(mid%column)
列
const searchMatrix = (matrix, target) => {
const row = matrix.length;
const column = matrix[0].length;
let start = 0,
end = row * column - 1;
while (start <= end) {
let mid = ~~((start + end) / 2);
let midNum = matrix[~~(mid / column)][~~(mid % column)];
if (midNum === target) return true;
else if (midNum > target) end = mid - 1;
else if (midNum < target) start = mid + 1;
}
return false;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14