[每日一题]74.搜索二维矩阵

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

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

举例:

202303071

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

举例2:

202303072

输入: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

Solutions

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        //暴力遍历
        int m = matrix.length;
        int n = matrix[0].length;

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == target){
                    return true;
                } 
            }
        }
        return false;
    }
}
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        //该方法还适用于每行元素数量不固定时
        int m = matrix.length;
        int n = matrix[0].length;
        int left = 0;
        int right = m - 1;
        //创建变量记录所在行值,最后一个小于目标值的行
        int row = 0;

        //对第一列二分查找
        //while不取等号避免左指针比右指针差一时left = mid陷入循环
        while (left < right) {
            //此处的+1是为避免left = mid时陷入循环
            int mid = (right - left + 1) / 2 + left;

            if (matrix[mid][0] == target) {
                return true;
            }
            //赋left = mid为避免left一直右移而错过目标行
            else if (matrix[mid][0] < target) {
                left = mid;
                row = left;

            } else {
                right = mid - 1;
            }
        }

        //根据行值二分查找该行
        left = 0;
        right = n - 1;
        while (left <= right) {
            int mid = (right - left) / 2 + left;

            if (matrix[row][mid] == target) {
                return true;
            } else if (matrix[row][mid] < target) {

                left = mid + 1;

            } else {
                right = mid - 1;
            }
        }
        return false;
    }
}
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        //将二维矩阵看做一维

        int m = matrix.length;
        int n = matrix[0].length;

        int left = 0;
        int right = m * n - 1;

        while (left <= right) {

            int mid = (right - left) / 2 + left;
            
            //根据mid值在一维数组中的位置推出该值在二维数组的行列
            int row = mid / n;
            int col = mid % n;


            if (matrix[row][col] == target) {
                
                return true;
                
            } else if (matrix[row][col] < target) {
                
                left = mid + 1;
                
            } else {
                
                right = mid - 1;
                
            }
        }

        return false;
    }
}

Ideas

  • 方法一:两次二分查找

由于每行的第一个元素大于前一行的最后一个元素,且每行元素是升序的,所以每行的第一个元素大于前一行的第一个元素,因此矩阵第一列的元素是升序的。

我们可以对矩阵的第一列的元素二分查找,找到最后一个不大于目标值的元素,然后在该元素所在行中二分查找目标值是否存在。

  • 方法二:一次二分查找

若将矩阵每一行拼接在上一行的末尾,则会得到一个升序数组,我们可以在该数组上二分找到目标元素。

代码实现时,可以二分升序数组的下标,将其映射到原矩阵的行和列上。