《剑指Offer》面试题3:二维数组中的查找(行列分别有序数组的二分查找)

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

例如:

如果在这个数组中查找7,返回true。查找3,返回false。

1289
24912
471013
681115
书中提到了这种二分查找的方法,但是书中说二分查找会导致下次查找两个互相重叠的区域。

我这个方法虽然能避免了相互重叠的区域,但是效率没有书上的算法好,但是作为一个锻炼写递归程序的机会也是不错的。


深色的为中心元素,有三种情况。

1.要找的值正好是中心元素

直接返回真。

2.要找的值大于中心元素,如图(a)

将(a)灰色部分进行查找。

分为两个矩形区域,如图横线,竖线所示。

3.要找的值小于中心的值,如图(b)

将(b)灰色部分进行查找。

分为两个矩形区域,如图横线,竖线所示。

查找不规则的区域需要知道一下信息:区域左上角的绝对坐标,区域的长 与 宽。所以我们可以设定一下函数原型。

bool BinarySearchMat(int* mat,int beginR,int beginC,int sumR,int sumC,int val);
根据上述的三种情况,写得一下代码。

bool BinarySearchMat(int* mat,int beginR,int beginC,int sumR,int sumC,int val)
{
	if (sumC <= 0 || sumR <=0)
	{
		return false;
	}
	int halfR = sumR / 2;
	int halfC = sumC / 2;
	int midR = beginR + halfR;
	int midC = beginC + halfC;
	if (val == mat[ midR * N + midC])
	{
		return true;
	}
	if(val < mat[midR * N + midC])   // define N = 4;
	{   //(b)图上面部分(横线)
		if(BinarySearchMat(mat,beginR,beginC,halfR,sumC,val))
			return true;
		if (BinarySearchMat(mat,midR,beginC,sumR - halfR ,halfC ,val))//(b)图左边部分(竖线)
			return true;

	}
	else
	{// val > mat[midR * N + midC]  
		//(a)图下面部分(横线)
		if(BinarySearchMat(mat,midR + 1,beginC,sumR - halfR - 1,sumC,val))
			return true;
<span style="white-space:pre">		</span>//(a)图右边部分(竖线)
		if (BinarySearchMat(mat,beginR,midC + 1,halfR + 1,sumC - halfC - 1,val))
			return true;

	}
	return false;
}
测试驱动代码:
int main()
{
	if(BinarySearchMat(arr[0],0,0,4,4,15))
		cout<<"true"<<endl;
	else 
		cout<<"false"<<endl;

	if(BinarySearchMat(arr[0],0,0,4,4,7))
		cout<<"true"<<endl;
	else 
		cout<<"false"<<endl;

	if(BinarySearchMat(arr[0],0,0,4,4,3))
		cout<<"true"<<endl;
	else 
		cout<<"false"<<endl;
	return 0;
}
完整程序(环境:VS2012)
/*
	二维数组的查找,
	二维数组每行递增,每列递增
*/
#include <iostream>
int arr[4][4] = {1,2,8,9,2,4,9,12,4,7,10,13,6,8,11,15};

const int N = 4;
bool BinarySearchMat(int* mat,int beginR,int beginC,int sumR,int sumC,int val);
using namespace std;
int main()
{
	if(BinarySearchMat(arr[0],0,0,4,4,15))
		cout<<"true"<<endl;
	else 
		cout<<"false"<<endl;

	if(BinarySearchMat(arr[0],0,0,4,4,7))
		cout<<"true"<<endl;
	else 
		cout<<"false"<<endl;

	if(BinarySearchMat(arr[0],0,0,4,4,3))
		cout<<"true"<<endl;
	else 
		cout<<"false"<<endl;
	return 0;
}

bool BinarySearchMat(int* mat,int beginR,int beginC,int sumR,int sumC,int val)
{
	if (sumC <= 0 || sumR <=0)
	{
		return false;
	}
	int halfR = sumR / 2;
	int halfC = sumC / 2;
	int midR = beginR + halfR;
	int midC = beginC + halfC;
	if (val == mat[ midR * N + midC])
	{
		return true;
	}
	if(val < mat[midR * N + midC])
	{
		if(BinarySearchMat(mat,beginR,beginC,halfR,sumC,val))
			return true;
		if (BinarySearchMat(mat,midR,beginC,sumR - halfR ,halfC ,val))
			return true;

	}
	else
	{// val > mat[midR * N + midC]
		//xia
		if(BinarySearchMat(mat,midR + 1,beginC,sumR - halfR - 1,sumC,val))
			return true;

		if (BinarySearchMat(mat,beginR,midC + 1,halfR + 1,sumC - halfC - 1,val))
			return true;

	}
	return false;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值