Q60- code74- 搜索二维矩阵
实现思路
1 一维映射 二分法
1.1 映射二维后纵坐标取模后不需要-1的原因,举例说明:
- m = 3, n = 4
- 矩阵按行展开为一维数组:[1, 3, 5, 7, 10, 11, 16, 20, 23, 30, 34, 60]
- 一维索引: 0 1 2 3 4 5 6 7 8 9 10 11
第一轮循环: mid = (-1 + 12) >> 1 = 5 mid = 5 对应一维数组中索引5的位置,值为11 转换为二维坐标: 行坐标 = ~~(5 / 4) = 1 列坐标 = 5 % 4 = 1
所以访问 matrix[1][1] = 11 ✓
2 行列收缩法
- 从右上角开始搜索,先确定行,再收缩列
参考文档
代码实现
1 方法1- 一维映射 二分法
- 时间复杂度:O(logn)
- 空间复杂度:O(1)
function searchMatrix(matrix: number[][], target: number): boolean {
const m = matrix.length, n = matrix[0].length;
let l = -1, r = m * n;
while (l + 1 < r) {
let mid = (l + r) >> 1;
// 易错点1:由于二维数组也是从0开始索引的,所以列索引取模后不需要-1
const x = matrix[~~(mid / n)][mid % n];
if (x === target) return true;
if (x > target) {
r = mid;
} else {
l = mid;
}
}
return false;
}
2 方法2- 行列收缩法
- 时间复杂度:O(m + n)
- 空间复杂度:O(1)
function searchMatrix(matrix: number[][], target: number): boolean {
const m = matrix.length, n = matrix[0].length;
// 从右上角开始搜索,先确定行,再收缩列
let row = 0, col = n - 1;
while (row < m && col >= 0) {
const x = matrix[row][col];
if (x === target) return true;
// 当前行的最大值 小于目标值,(排除此行)向下移动行
if (x < target) {
row++;
} else {
// 当前行的最大值 大于目标值,(排除此列)向左移动列
col--;
}
}
return false;
}
Q61- code240- 搜索二维矩阵 II
实现思路
1 行列收缩法
- 从右上角开始搜索,先确定行,再收缩列
参考文档
代码实现
1 方法1- 行列收缩法
- 时间复杂度:O(m + n)
- 空间复杂度:O(1)
function searchMatrix(matrix: number[][], target: number): boolean {
const m = matrix.length, n = matrix[0].length;
let row = 0, col = n - 1;
while (row < m && col >= 0) {
const x = matrix[row][col];
if (x === target) return true;
x < target ? row++ : col--;
}
return false;
}
2 变种题解法:矩阵有重复值,要找到横纵坐标和最小的目标值
- 解法: 从左上角 依次探测
interface Position {
row: number;
col: number;
}
function findMinSumPosition(
matrix: number[][],
target: number
): Position | null {
const m = matrix.length, n = matrix[0].length;
let row = 0, col = 0;
// 从左上角开始,每次向右或向下移动
while (row < m && col < n) {
// 找到一个目标值,由于我们是从左上角开始,这就是和最小的位置
if (matrix[row][col] === target) return { row, col };
// 决定下一步移动方向
// 如果右边的值小于等于目标值,优先向右移动
if (col + 1 < n && matrix[row][col + 1] <= target) {
col++;
} else if (row + 1 < m && matrix[row + 1][col] <= target) {
// 否则如果下边的值小于等于目标值,向下移动
row++;
} else {
// 如果两个方向都大于目标值,说明当前路径不可能找到目标值
break;
}
}
return null;
}