搜索二维矩阵

109 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

题目描述


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

每行中的整数从左到右按升序排列。 每行的第一个整数大于前一行的最后一个整数。  

示例 1:

image.png

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

示例 2:

image.png

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

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 100
  • -104 <= matrix[i][j], target <= 104

解法1

  • arr.slice(-1)[0] 获取数组的最后一个值 效率比arr[arr.length-1]高
  • 遍历每一行,判断值在第几行
  • includes判断行里是否有target
var searchMatrix = function (matrix, target) {
  let i = 0,
    bool = false,
    len = 0;
  while (i < matrix.length) {
    let arr = matrix[i];
    let arr2 = matrix[i + 1];

    if (arr[0] <= target && target <= arr.slice(-1)[0]) {
      //值可能在第i行
      bool = arr.includes(target);
      if (bool) {
        return bool;
      }
    }

    i++;
  }

  return bool;
};

image.png

解法1 升级

  • 用 inArr 替换 includes 方法,效率有显著提升
var searchMatrix = function (matrix, target) {
  let i = 0,
    bool = false,
    len = 0;
  while (i < matrix.length) {
    let arr = matrix[i];
    let arr2 = matrix[i + 1];

    if (arr[0] <= target && target <= arr.slice(-1)[0]) {
      //值可能在第i行
      bool = inArr(arr,target);
      if (bool) {
        return bool;
      }
    }

    i++;
  }

  return bool;
};
var inArr = function (arr, target) {
  for (let i of arr) {
    if (i == target) {
      return true;
    } else if (i > target) {
      return false;
    }
  }
  return false;
};

image.png

解法2 二分查询

如解法1,我们可以用二分法进阶,减小一半的便利

/**
 * @param {number[][]} matrix
 * @param {number} target
 * @return {boolean}
 */
var searchMatrix = function (matrix, target) {
  let left = 0,
    right = matrix.length - 1;
  let bool = false;
  while (left <= right) {
    let mid = parseInt((left + right) / 2);
    let arr = matrix[mid];
    if (arr[0] <= target && target <= arr.slice(-1)[0]) {
      let left2 = 0,
        right2 = arr.length;
      while (left2 <= right2) {
        let mid2 = parseInt((left2 + right2) / 2);

        if (arr[mid2] > target) {
          //前半段
          right2 = mid2 - 1;
        } else if (arr[mid2] < target) {
          left2 = mid2 + 1;
        } else {
          bool = true;
          return bool;
        }
      }
      return bool;
    } else if (target < arr[0]) {
      //前半段
      right = mid - 1;
    } else {
      //后半段
      left = mid + 1;
    }
  }

  return bool;
};

image.png

解法3 最优解

  • 从最后一行第0列开始遍历取值num
  • 如果 target > num ,则表示 target 可能在当前行
  • 如果 target < num ,则表示 target 可能不在当前行,取上一行第值再判断
  • 如果想等返回 true,否则 false
/**
 * @param {number[][]} matrix
 * @param {number} target
 * @return {boolean}
 */
var searchMatrix = function (matrix, target) {
  //获取中间的元素 比较大小
  let i = matrix.length - 1, //行
    j = 0; //列
  while (i >= 0 && j < matrix[0].length) {
    let num = matrix[i][j];

    if (num == target) {
      return true;
    } else if (num < target) {
      //上移动
      j++;
    } else {
      i--;
    }
  }

  return false;
};

image.png

总结

很简单的一道数学题,记录下,方便后期查阅