问题:在有序的二维数组中寻找目标值
类型:数组搜索问题
分析:有序数组查值,最快的是二分搜索。
1.可以使用二分搜索寻值,但是数组为二维数组,找中间值mid的索引不方便。解决方案就是,先算出mid,将其转换为对应的二维索引,可得matrix[mid/col][mid%col],该位置上的值即为中间值。
时间复杂度:O(log(mn)),m行数,n为列数
空间复杂度:O(1)
2.第二种二分查找则是先确认target在哪一行,再确认target在那一列。即先进行行二分,再进行列二分。
时间复杂度:O(log(m)+log(n))=O(log(mn))
空间复杂度:O(1)
3.第三种方法则是从右上角或左下角开始查值,这是因为此处的值具有两重属性:以左下角为例,该值为当前行的最小值,且为当前列的最大值。所以用该位置上的值,一次比较可消除一行或者一列的元素。速度极快。
时间复杂度:O(m+n),最坏情况为从左下角走到右上角
空间复杂度:O(1)
收获:
1.对二维数组进行二分查找时,该如何寻找到mid在数组中的索引,行索引:mid/col 列索引:mid%col
2.进行选择时,尽量挑选具有更多属性的元素进行比较,从而达到消除更多状态的目的。
3.尝试从右往左,从上至下的搜索策略,有时会有意想不到的结果。
代码:
//一次二分查找
bool searchMatrix(int **maxtrix,int matrixSize,int *matrixColSize,int target){
if(!matrixSize||!matrixColSize)
return false;
int lo=0,hi=matrixSize*(*matrixColSize)-1;
int col=(*matrixtColSize);
while(lo<=hi){
int mid=lo+((hi-lo)>>1);
if(matrix[mid/col][mid%col]<target)
lo=mid+1;
else if(target<matrix[mid/col][mid%col])
hi=mid-1;
else
return true;
}
return false;
}
//两次二分查找
bool searchMatrix(int **matrix,int matrixSize,int *matrixColSize,int target){
if (!matrixSize || !(*matrixColSize)) return false;
int left = 0, right = matrixSize - 1;
while (left <= right) {
int mid_row = left + ((right - left) >> 1);
if (matrix[mid_row][0] > target) {
right = mid_row - 1; // 向上找
}
else if (matrix[mid_row][(*matrixColSize)-1] < target) {
left = mid_row + 1; // 向下
}
else {
int lo=0,hi=(*matrixColSize)-1;
while(lo<=hi){
int mid_col=lo+((hi-lo)>>1);
if(matrix[mid_row][mid_col]<target)
lo=mid_col+1;
else if(target<matrix[mid_row][mid_col])
hi=mid_col-1;
else
return true;
}
return false;
}
}
return false;
}
//从左下角走
bool searchMatrix(int **matrix,int matrixSize,int *matrixColSize,int target){
if(!matrixSize || !(*matrixColSize)) return false;
int row=matrixSize-1,col=0;
while(0<=row&&col<(*matrixColSize)){
if(matrix[row][col]<target)
col++;
else if(target<matrix[row][col])
row--;
else
return true;
}
return false;
}