题目描述
原文链接:https://leetcode-cn.com/problems/search-a-2d-matrix/
编写一个高效的算法来判断 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
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-104 <= matrix[i][j], target <= 104
题目分析
题意大致就是在一个二维数组中查询是否有目标值,简单暴力的做法当然是双重for循环遍历每个值,在题目数据范围内是不会超时的,复杂度:,略做优化,在外层循环中判断一下此数组范围是否包含target,包含再进入其中遍历,复杂度:
,理论上已经满足大部分情况了,但是仍然有更优秀的方案解决:对于这样的有序数组(二维数组)中的查找,我们首先就该想一下如何二分,因为二分查找的复杂度通常来说是
。那么这道题我们用二分的思路来思考有两种方法:
1.将二维数组整理为一维数组,然后二分查找
解析:这样做虽然在查找的时候很快捷,复杂度:,但是整理的过程需要n+m的复杂度,有些本末倒置的味道,如果像本题目一样只查询一次,那么我们不应该选择这样的方法。
2.在二维数组上分别做二分查找,也就是先二分第一维数组,再二分第二维数组,听起来可能复杂,但实际上就是写了两次二分查找,复杂度:
代码实现
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int n = matrix.length;
int m = matrix[0].length;
// System.out.println("n:"+n+" m:"+m);
int i_left=0; //一维左右指针
int i_right=n-1;
int j_left=0; //二维左右指针
int j_right=m-1;
int i_mid=0;
int j_mid=0;
while(i_left<=i_right){
i_mid = i_left+(i_right-i_left)/2;
// System.out.println("i_mid:"+i_mid);
if(matrix[i_mid][0]<=target&&matrix[i_mid][m-1]>=target){ //答案在此一维数组中
// System.out.println("在一维数组:"+i_mid);
j_left = 0;
j_right = m-1;
while(j_left<=j_right){
j_mid = j_left+(j_right-j_left)/2;
// System.out.println("j_mid:"+j_mid);
if(matrix[i_mid][j_mid]==target){
return true;
}else if(matrix[i_mid][j_mid]>=target){
j_right = j_mid-1;
}else {
j_left = j_mid+1;
}
}
return false;
}else if(matrix[i_mid][0]>target){ //在左边的数组中
i_right = i_mid-1;
}else{
i_left = i_mid+1; //在右边的数组中
}
}
return false;
}
}
写在最后
比较简单的二分题目,思路比较重要,要对有序数组保持敏感,优先二分。
欢迎交流,欢迎评论