我是从九度OJ上面看到这个题目的,如果只是简单的想AC这道题目,介于OJ平台只关注输入输出,则很容易AC这道题目。我是把这道题目看做是一道面试题来解决的,先来看下题目吧:
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
输入可能包含多个测试样例,对于每个测试案例,
输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的矩阵的行数和列数。
输入的第二行包括一个整数t(1<=t<=1000000):代表要查找的数字。
接下来的m行,每行有n个数,代表题目所给出的m行n列的矩阵(矩阵如题目描述所示,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。
对应每个测试案例,
输出”Yes”代表在二维数组中找到了数字t。
输出”No”代表在二维数组中没有找到数字t。
首先,因为数组的每一行和每一列都是递增的所以可以发现如下的规律:
数字7是大矩阵的最小值,13是小矩阵的最小值,所以我们的思路就是先让查找的数x跟二维数组的对角线上的值进行比较(找到数组中对角线上第一个大于x的数的位置来缩小查找的范围)比如,我们查找12,那么查找的范围就可以锁定在两个部分,如下图所示:
此时,我们只要在这两部分中查找x即可,观察可发现这两个部分一个是一行数据(可视为一维数组)和一个是小矩阵。前一部分可以用二分查找(有序),后一部分可以直接遍历(应该还有更好的方法,我实现的时候是直接遍历)。
由于题目对m和n的大小关系没有做限制,这就增加了题目的难度(即找到二维数组中第一个大于x的数的位置边困难了),我的解决思路是根据m和n的大小关系分三种情况,
当m=n时最简单,在此不提,另外两种情况,分别是找一个小的方型矩阵,如果没有找到要找的位置,那么改变循环变量的值,继续在下一个小方型矩阵中寻找,直到没有小的方型矩阵为止。下面给出一个m>n的大致查找过程:
主要解题思路如上所述,下面给出C语言实现的完整代码(附注释)
#include
#include
long a[1000][1000];
int m,n;
//二分查找
int binarySearch(int tm1,int tn1,long x)
{
int s,e,mid;
s=tn1+1;
e=n-1;
while(s<=e)
{
mid=(s+e)/2;
if(a[tm1][mid]==x)
return 1;
else if(a[tm1][mid]n)
{
tm=0;
tn=0;
//查找位置的过程
while(tmx)
{
break;
}
if(tn==n-1)
{
tn=0;
++tm;//进入下一个小型方阵
}
else
{
++tn;
++tm;
}
}
//查找位置的过程
if(tm==m)
{
return binarySearch(tm-1,0,x);
}
else
{
//找到位置后,分别对两部分进行查找
r1=binarySearch(tm-1,tn-1,x);//二分查找
r2=binarySearch2(tm,tn-1,x);//小矩阵遍历
return (r1+r2);
}
}
else if(mx)
{
break;
}
if(tm==m-1)
{
tm=0;
++tn;
}
else
{
++tn;
++tm;
}
}
if(tn==n)
{
return binarySearch2(tn-1,0,x);
}
else
{
r1=binarySearch(tm-1,tn-1,x);
r2=binarySearch2(tm,tn-1,x);
return (r1+r2);
}
}
else
{
tm=0;
tn=0;
while(tmx)
{
break;
}
++tn;
++tm;
}
if(tm==m)
{
return 0;
}
else
{
r1=binarySearch(tm-1,tn-1,x);
r2=binarySearch2(tm-1,tn-1,x);
return (r1+r2);
}
}
}
int main()
{
int i,j;
long x;
while(scanf("%d %d",&m,&n)!=EOF)
{
scanf("%ld",&x);
for(i=0;i