【LeetCode】74. 搜索二维矩阵(Medium)

94 篇文章 0 订阅
  • 74. 搜索二维矩阵

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

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

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

示例 1

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

输出:true

示例 2

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

输出:false

 

思路:

方法一:两次二分查找【通用,必会】

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

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

// 法1:二分*2次(先第一列-获取行号row_i,后在row_i行继续二分查找target) 
public boolean searchMatrix_v1(int[][] matrix, int target) {
    int row_i = BinSearch1_col0(matrix, target);
    // System.out.println(row_i);
    if (row_i == -1) return false;
    return BinSearch2_row(matrix[row_i], target);
}

//  找到最后一个不大于target的matrix第一列元素
// 二分1st - [left, mid-1], [mid, right]
private int BinSearch1_col0(int[][] matrix, int target) {
    int start = -1, end = matrix.length - 1;
    while (start < end) {
        int mid = (start + 1) + end >> 1; // 
        if (matrix[mid][0] <= target)
            start = mid;
        else end = mid - 1;
    }
    return start;
}
// 二分2nd - [left, mid-1], mid, [mid+1, right]
private boolean BinSearch2_row(int[] row, int target) {
    int start = 0, end = row.length - 1;
    while (start <= end) {
        int mid = start + end >> 1;
        if (row[mid] == target)
            return true;// mid;
        else if (row[mid] < target)
            start = mid+1;
        else end = mid-1;
    }
    return false;
}

 

解法二【推荐】 那么,如何让方法高效呢?

根据题目我们知道,如果把a + 1行的头部连接到a行的末尾,那么我们可以得到一行递增的数值。也就是说,如果我们把矩阵中每一行都按照刚刚说的方式拼接在一起,那么一个矩阵就变成了递增数组

我们对于这个递增数组进行二分搜素,就可以得到答案。下面是代码:

// 法2:二分*1次【推荐】 
public boolean searchMatrix_v2_1(int[][] matrix, int target) {
    int m = matrix.length, n = matrix[0].length;
    int start = 0, end = m * n - 1;
    while (start + 1 < end) {
        int mid = start + end >> 1;
        // row = mid / n, col = mid % n
        int mid_val = matrix[mid / n][mid % n]; 
        if (mid_val == target) return true;
        else if (mid_val < target)
            start = mid;
        else end = mid;
    }
    if (matrix[start / n][start % n] == target) return true;
    else if (matrix[end / n][end % n] == target) return true;
    return false;
}

// 法2-2:(二分模板3)- [left, mid-1], mid, [mid+1, right]
public boolean searchMatrix_v2_2(int[][] matrix, int target) {
    int m = matrix.length, n = matrix[0].length;
    int start = 0, end = m * n - 1;
    while (start <= end) {  // [left, mid-1], mid, [mid+1, right]
        int mid = start + end >> 1;
        int mid_val = matrix[mid / n][mid % n]; // row = mid / n, col = mid % n
        if (mid_val == target) return true;
        else if (mid_val < target)
            start = mid+1;
        else end = mid-1;
    }
    return false;
}

解法三

我们能否根据特殊位置的特征来寻找元素?比如以右上角或左下角的元素为标准,开始搜索?

我们分析一下右上角的元素。

如果我们一开始拿右上角的元素做比较,我们的目标(target)如果大于右上角元素,那么target应该在右上角元素的下方;如果小于,那么在右上角元素的左边。我们通过控制行row和列column,可以以右上角元素为初始标度,寻找target是否存在。

https://leetcode-cn.com/problems/search-a-2d-matrix/solution/ti-yi-lei-jie-yi-wen-dai-ni-wan-cheng-li-tux0/

// 法3:(BST搜索)
public boolean searchMatrix(int[][] matrix, int target) {
    int row = 0, col = matrix[0].length - 1;
    // 以右上角为起点root, 看作BST(查找方向: 向下row++/向左col--)
    while (row < matrix.length && col >= 0) {
        if (matrix[row][col] == target)  return true;
        else if (matrix[row][col] < target)
            row++; // 如果目标值大,那么下一步往下找
        else if (matrix[row][col] > target)
            col--; // 如果目标值小,那么下一步往左找   
    }
    return false;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值