更多题目请点链接:《剑指offer》目录索引
问题描述:
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数
分析问题:
从问题描述中,可以确定一下几点:
1)在二维数组中查找整数,根据学过的知识可知,二维数组可看做一维数组,故此题可在一维数组中求解
2)此数组的特点是从左到右递增排序,从上到下递增排序;故有几个特殊的位置需要注意:左上角,右上角,左下角,右下角;这几个位置便是解题的突破点
3)左上角和右下角分别是数组中最小和最大的整数,右上角元素为当前列最小,所在行最大,左下角则相反
解题思路:
由上述题目的分析,我们可任意选取4个特殊位置其中一个开始查找;例如从左下角开始查找:左下角为当前行(row)最小,当前列(col)大元素(a),如果待查找元素(key)小于 a, 去 row-1 行查找,如果待查找元素(key)大于 a,去 col+1 列查找(下面附图)
》查找4
》查找11
》查找7
具体代码:
int Find(int **arr, int key)
{
assert(*arr);//防止数组为空
int row = 4-1;//左下角
int col = 0;
while (row >=0 && col < 4)
{
if (arr[row][col] == key)
{
return 1;//如果找到,返回1
}
else if (arr[row][col]<key)
{
++col;//如果当前元素小于待查找元素,在col+1列找
}
else
{
--row;//如果当前元素大于待查找元素,在row-1行找
}
}
return -1;
}
进阶:一维数组实现上面函数
int YangFind1(int *arr, int row, int col, int key)
{
if(arr == NULL)
return -1;
if ( row >= 0 && col >= 0)
{
int i = 0;//控制行
int j = col - 1;//控制列
while (i < row&& j >= 0)
{
if (arr[i*col + j] == key)
{
return i*col + j;//找到返回下标
}
else if (key>arr[i*col + j])
{
++i;
}
else
{
--j;
}
}
}
return -1;
}
分析:根据前面分析问题可知,二维数组可看做一维数组,故可将一维数组转化为二维数组进行求解,此时需注意下标的控制(附图)
测试用例:
注意:测试用例设计时,要做到全面,不能遗漏;查找时,最小值,最大值,不在数组中的值以及数组是空数组
1)二维数组实现
void Test()
{
int arr[ROW][COL] = {
{ 1, 2, 8, 9 },
{ 2, 4, 9, 12 },
{ 4, 7, 10, 13 },
{ 6, 8, 11, 15 },
};
printf("%d \n", Find(arr, 1));
printf("%d \n", Find(arr, 7));
printf("%d \n", Find(arr, 10));
printf("%d \n", Find(arr, 13));
printf("%d \n", Find(arr, 15));
printf("%d \n", Find(arr, 0));
printf("%d \n", Find(NULL, 0));
}
2)一维数组实现
void Test1()
{
int a[] = { 1, 2, 8, 9, 2, 4, 9, 12, 4, 7, 10, 13, 6, 8, 11, 15 };
printf("%d \n", YangFind1(a, 4, 4, 1));
printf("%d \n", YangFind1(a, 4, 4, 7));
printf("%d \n", YangFind1(a, 4, 4, 15));
printf("%d \n", YangFind1(NULL, 4, 4, 0));
}
结果:
说明:第一张图显示结果断言失败,因为在最后传了空指针NULL过去,所以发生报错
assert(*arr);//防止数组为空
第二张图有两个-1,这里也是传了一个空指针,但处理时将NULL当成数组的一种状态,如果是空,则返回-1
if(arr == NULL)
return -1;