链接:https://www.nowcoder.com/questionTerminal/abc3fe2ce8e146608e868a70efebf62e
来源:牛客网
两种思路
一种是:
把每一行看成有序递增的数组,
利用二分查找,
通过遍历每一行得到答案,
时间复杂度是nlogn
我之前写二分法都是想着用递归来实现,不得不重新定义一个函数,其实不用,只需要用一个while循环就行了。
public class Solution {
public boolean Find(int [][] array,int target) {
for(int i=0;i<array.length;i++){
int low=0;
int high=array[i].length-1;
while(low<=high){
int mid=(low+high)/2;
if(target>array[i][mid])
low=mid+1;
else if(target<array[i][mid])
high=mid-1;
else
return true;
}
}
return false;
}
}
另外一种思路是:
利用二维数组由上到下,由左到右递增的规律,
本来是以为:比你大有两种可能,①在你下面 ②在你右边。所以这就造成了编程的难度。
但是!!!如果规定先从左下角开始比较,那么这种可能性就只能有一个了!
那么选取左下角的元素a[row][col]与target进行比较,
当target小于元素a[row][col]时,那么target必定在元素a所在行的左边,
即col--;
当target大于元素a[row][col]时,那么target必定在元素a所在列的下边,
即row++;
bool Find(int target, vector<vector<int> > array) {
int row=array.size()-1;
int col=array[0].size()-1;
int i=row;
int j=0;
while(i>=0 && j<=col){
if(target==array[i][j])
return true;
else if(target>array[i][j])
j++;
else
i--;
}
return false;
}
另外一道二分查找的题:
大致思路:
先对每一行的第一个元素来进行二分查找,找到target所在的行,然后对该行进行二分查找。
经过模拟,我发现在第一种(对第一列的)二分查找中,二分查找的if语句if(low<=high)需要修改,因为存在一种情况是:
1 2 3 4
5 6 7 8
此时low=1,high=2,要查找的数是3,但matrix[mid][0]总是等于1,你不能让low = mid+1,因为那样low变成2会错过。所以等到low==high-1就应该停下循环了。通过模拟,发现停下来之后,target有可能在low,有可能在high==low+1行上。进行两次在行上的二分查找。这个二分查找就是常规的了,不过要注意if(low<=high),不要写落了=,因为比如对于[1,3],target是3,如果写掉=则刚刚找到low==high==3所在的位置,就退出循环了。
总之,这种情况举个例子多模拟几下,注意常规的二分查找if(low<=high)
AC代码:
class Solution {
public:
bool searchMatrix(vector<vector<int> > &matrix, int target) {
if(matrix.size()==0)
return false;
if(matrix.size()==1 && matrix[0].size()==1 && target == matrix[0][0])
return true;
//对每行第一个元素二分查找
int row = matrix.size();
int col = matrix[0].size();
int low=0;
int high=row-1;
while(low<high && low+1!=high)
{
int mid = (low+high)/2;
if(matrix[mid][0]==target)
return true;
if(matrix[mid][0]<target)
low=mid; //不能low=mid+1,因为这不代表low排上没有target
if(matrix[mid][0]>target)
high = mid-1; //可以high=mid-1,因为这代表high排上没有target
}
//现在肯定满足在low或者high排上
//先找Low排
//在low排上进行二分查找
int left = 0;
int right = col-1;
while(left<=right)
{
int mid = (left+right)/2;
if(matrix[low][mid]==target)
return true;
if(matrix[low][mid]<target)
left=mid+1;
if(matrix[low][mid]>target)
right = mid-1;
}
//在high排上进行二分查找
left =0;
right = col-1;
while(left<=right)
{
int mid = (left+right)/2;
if(matrix[high][mid]==target)
return true;
if(matrix[high][mid]<target)
left=mid+1;
if(matrix[high][mid]>target)
right = mid-1;
}
return false;
}
};