Q60- code74- 搜索二维矩阵 + Q61- code240- 搜索二维矩阵 II

49 阅读3分钟

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 行列收缩法

  • 从右上角开始搜索,先确定行,再收缩列

参考文档

01- 方法1参考文档

代码实现

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 行列收缩法

  • 从右上角开始搜索,先确定行,再收缩列

参考文档

01- 方法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;
}