【算法】在特殊二维数组查询
特定二维数组查询问题
Cracking the Code Interview 11.6
题目描述:
给一个二维的数组,数组中的每一行和每一列都是递增的,怎样找到某个元素的坐标? 例如下面这种情况:
1 | 3 | 5 | 7 | 9 |
2 | 5 | 6 | 8 | 10 |
4 | 5 | 7 | 10 | 11 |
6 | 6 | 8 | 14 | 15 |
7 | 9 | 12 | 16 | 17 |
解析:
在这个特定的数组里,很容易想到的是二分查找。例如我们要在数组中找16这个数。在上例中,我们先定位到中间的元素7,16>7,我们继续在7的右侧和下侧寻找,我们可以一直在对角线上找,比如我们再找14,因为16>14,所以在14的右下,继续找17,在17的左上,这样我们就定位到两个新的数组中,如此进行二分查找。
另一种巧妙的方法是从右上角开始寻找,这种想法非常巧妙,需要的时间是O(m+n),至于为什么会想到这个呢?因为右上或者左下的点有这样的特点,以右上为例,其下方均是大于它的点,左侧均是小于它的点,意味着我们用它进行比较后,无论情况如何,每次比较至少能够过滤掉一行。其实直观上很难想,遇到题还是举例多试一些情况比较好。
具体代码如下:
#include <stdio.h>
#include "arrayAndString.h"
void searchInMatrix(int matrix[][5],int width,int height,int target,int *pos_x,int *pos_y){
//查找到的位置会返回给*pos_x和*pos_y,如果没有找到,返回(-1,-1)
if (matrix == NULL) return ;
int x1 = 0;
int x2 = width - 1;
while (x2 >= 0 && x1 <= height - 1) {//确保x和y在矩形内
if (target == *(*(matrix+x1)+x2)){
//case1: 找到了
*pos_x = x2;
*pos_y = x1;
return;
}else if(target < matrix[x1][x2]){
//case2:target要小,在左侧的一个位置去找
x2--;
}else{
//case2:target要大,在下方的一个位置去找
x1++;
}
}
*pos_x = -1;
*pos_y = -1;
}
void testSearchInMatric(){
int a[4][5] ={1,2,3,4,5,2,3,4,6,7,3,4,5,8,9,4,7,8,9,10};
//显示数组
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 5; j++) {
printf("%d\t",a[i][j]);
}
printf("\n");
}
int x,y;//用来保存搜索到的位置
searchInMatrix(a,5,4,8,&x,&y);
printf("find in (%d,%d)\n",x+1,y+1);
}