LeetCode 刷题笔记【74. 搜索二维矩阵】

913 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

题目

leetcode-cn.com/problems/se…

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

每行中的整数从左到右按升序排列。

每行的第一个整数大于前一行的最后一个整数。

示例

20220402150543.jpg

输入: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3

输出: true

常规遍历

逐个遍历,这实现起来很简单,但最不高效,直接略过。

var searchMatrix = function(matrix, target) {
  for (let x = 0; x < matrix.length; x++) {
    for (let y = 0; y < matrix[x].length; y++) {
      if (matrix[x][y] === target) {
        return true;
      }
    }
  }
  return false;
};

尝试调整下遍历顺序

结合矩阵生序的条件,仔细端详矩阵的特点。

设想一下,如果我们第一层遍历从后往前,即从最后一行到第一行开始遍历,当前行的第一个元素作为一个分界点,往上都是比他小的,往右都是比他大的。

首先比较当前行的第一个元素和目标值。

如果比目标值小,只需要再遍历当前行来寻找目标值,没找到的话直接 return false

否则就循环到上一行,继续比较直至结束。

这样很大程度上缩小了我们遍历的范围,提升了性能。

var searchMatrix = function(matrix, target) {
  for (let x = matrix.length - 1; x >= 0; x--) {
    if (matrix[x][0] === target) {
      return true;
    }
    if (matrix[x][0] < target) {
      for (let y = 1; y < matrix[x].length; y++) {
        if (matrix[x][y] === target) {
          return true;
        }
      }
      return false;
    }
  }
  return false;
};

利用二分查找继续优化

上面我们通过调整遍历的方向优化了一波性能,代码中,我们首先遍历了第一列的值,找到合适位置再遍历当前行。那么这两次查找我们可以尝试用二分查找来实现,这样性能可以又一次提升。

首先遍历第一列,得到目标行。

使用二分时有一点需要注意,当中间值小于目标值时,有两种情况:

1、目标值在下一行,跳到下一行 2、目标值在当前行,直接返回当前行

得到目标行后,再用二分法在目标行查找查找目标值即可。

var searchMatrix = function(matrix, target) {
  const binSearchCol = () => {
    let left = 0;
    let right = matrix.length - 1;
    while(left < right) {
      let mid = (left + right) >> 1;
      if (matrix[mid][0] === target) {
        return mid;
      }
      if (matrix[mid][0] < target) {
        // 目标值在当前行,直接返回当前行
        if (matrix[mid][matrix[mid].length - 1] >= target) {
          return mid;
        }
        left = mid + 1;
      } else {
        right = mid - 1;
      }
    }
    return left;
  }

  const colIndex = binSearchCol();

  let left = 0;
  let right = matrix[colIndex].length - 1;
  while(left < right) {
    let mid = (left + right) >> 1;
    if (matrix[colIndex][mid] === target) {
      return true;
    }
    if (matrix[colIndex][mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  if (matrix[colIndex][left] === target) return true;

  return false;
};

结语

从解题思路的一步步优化看来,二分法可以看作是查找类题目的最优解,后面遇到类似题目要第一时间想到二分法。