《剑指offer》【面试题3:二维数组中的查找】

面试题3:二维数组中的查找

数组基础点:
一种基本的数据结构,用于在一块连续的内存中并按照顺序存储数据。创建数组时,先指定数组的大小,然后根据数组的大小进行分配内存。即使在数组中只存储一个数字,也要为整个数组分配内存大小。所以数组的空间利用率不是很好,经常会有空闲的区域没有很好的利用而浪费掉。

但是数组的内存连续也有它的优点:可以根据下标在O(1)时间读、写任何元素,所以对于访问数组中的元素的效率还是很好的(这里说的是根据下标访问,列如:array[1];但是需要查找一个元素时,需要遍历整个数组,这时候时间复杂度就是O(n)了);

面试题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

分析:
对于这种事先,每一行每一列都是递增有序的二维数组,我们可以找临界点,作为突破口进行解决。所以根据观察得出,右上角是第一行最大的值,是最后一列最小的值,所以用这个点与所要查找的数字进行比较,来把这个二维数组的范围逐渐缩小,为什么选这个由上角呢,因为与一个数判断,结果要么是等于、大于、小于这三种情况,所以也就是说让你选的这个点有一个移动的方向,不能让它盲目的四处乱窜,对吧。右上角这个点左移可以使数值缩小,下移可以使数值增大,所以也就有了所谓的方向感,也符合判断结果的三个走向,通过移动,使移动的这个点与所要查找的值不断判断, 不断的缩小 范围,直到找到查找的数字,或者查找的范围缩小为空。
右上角为例:


图解:


#include <stdio.h>
#include <assert.h>
//从右上角可以查找
//array 数组名	  rows 行    cols列    number 查找的数字
bool TwoArrayFind_number(int *array,int rows,int cols,int number)
{
	bool count = false;
	assert(array != NULL);
	if (rows <= 0 && cols <= 0)
	{
		return -1;
	}
	int row = 0;
	int col = cols-1;//从右上角开始
	while(row < rows && col >= 0)
	{
		if (array[row * cols + col] == number)
		{
			count = true;
			break;
		}
		else if (array[row * cols + col] > number)
		{
			col--;//列左移一个格子
		}
		else
		{
			row++;//行下移一个格子
		}
	}
	return count;

}



int main()
{
	//测试用例 *谨记行移动一次乘以总列数(而不是变化的列)
	//判断编译器下的真假值
	printf("%d\n",true);//真为1
	int arr[17] = {1,2,8,9,2,4,9,12,4,7,10,13,6,8,11,15};
	//数组中介于最大值最小值之间
	printf("%d\n",TwoArrayFind_number(arr,4,4,7));
	//数组最小值
	printf("%d\n",TwoArrayFind_number(arr,4,4,1));
	//数组最大值
	printf("%d\n",TwoArrayFind_number(arr,4,4,15));
	//大于数组最大值,不存在数组中
	printf("%d\n",TwoArrayFind_number(arr,4,4,16));
	//小于数组最小值,不存在数组中
	printf("%d\n",TwoArrayFind_number(arr,4,4,0));
	//介于数组最大值与最小值之间,但是不存在数组中
	printf("%d\n",TwoArrayFind_number(arr,4,4,5));
	//特殊测试:空指针
	printf("%d\n",TwoArrayFind_number(NULL,4,4,15));
	return 0;
}
既然右上角可以,相应的左下角也可以:即左下角点与查找的数字比较所得结果的三种走向,要么相等、要么小于、要么大于。相等返回真,移动的点<查找的数字,右移; 移动的点>查找的数字,
上移。类似于由上角缩小范围,直到找到查找的数字,或者范围缩小为空返回假。
代码实现:
//从左下角可以查找
//array 数组名	  rows 行    cols列    number 查找的数字
bool TwoArrayFind_number2(int *array,int rows,int cols,int number)
{
	bool count = false;
	assert(array != NULL);
	if (rows <= 0 && cols <= 0)
	{
		return -1;
	}
	int row = rows-1;//从左下角开始
	int col = 0;
	while(col < cols && row >= 0)
	{
		if (array[col * rows + row] == number)
		{
			count = true;
			break;
		}
		else if (array[col * rows + row] > number)
		{
			row--;//行上移一个格子
		}
		else
		{
			col++;//列右移一个格子
		}
	}
	return count;

}



int main()
{
	//测试用例 *谨记列移动一次乘以总行数(而不是变化的行)
	//判断编译器下的真假值
	printf("%d\n",true);//真为1
	int arr[17] = {1,2,8,9,2,4,9,12,4,7,10,13,6,8,11,15};
	//数组中介于最大值最小值之间
	printf("%d\n",TwoArrayFind_number2(arr,4,4,7));
	//数组最小值
	printf("%d\n",TwoArrayFind_number2(arr,4,4,1));
	//数组最大值
	printf("%d\n",TwoArrayFind_number2(arr,4,4,15));
	//大于数组最大值,不存在数组中
	printf("%d\n",TwoArrayFind_number2(arr,4,4,16));
	//小于数组最小值,不存在数组中
	printf("%d\n",TwoArrayFind_number2(arr,4,4,0));
	//介于数组最大值与最小值之间,但是不存在数组中
	printf("%d\n",TwoArrayFind_number2(arr,4,4,5));
	//特殊测试:空指针
	printf("%d\n",TwoArrayFind_number2(NULL,4,4,15));
	return 0;
}
既然左下角、右上角都说了,不妨说一下左上角,其实左上角找也可以,逻辑思想更符合平常的理解,但是首先它要卡出一个范围,即把这个数字与两列进行比较,把一开始的大范围缩小,然后再按照右上角的方法进行“回退”,即下移或者左移,直到找到查找的数字为止。但是用左上角找注意的是,有序是指每一列、每一行。有时候会出现“漏掉”的可能,比如上述图中的'6'就是一个不错的测试用例,用在左上角查找时。(自己去发现吧偷笑


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值