301查找排序

题目1:

二分查找:

int BinarySearch(int array[], int n, int value)
{
    int left = 0;
    int right = n - 1;
    //如果这里是int right = n 的话,那么下面有两处地方需要修改,以保证一一对应:
    //1、下面循环的条件则是while(left < right)
    //2、循环内当 array[middle] > value 的时候,right = mid

    while (left <= right)  //循环条件,适时而变
    {
        int middle = left + ((right - left) >> 1);  //防止溢出,移位也更高效。同时,每次循环都需要更新。

        if (array[middle] > value)
        {
            right = middle - 1;  //right赋值,适时而变
        }
        else if(array[middle] < value)
        {
            left = middle + 1;
        }
        else
            return middle;
        //可能会有读者认为刚开始时就要判断相等,但毕竟数组中不相等的情况更多
        //如果每次循环都判断一下是否相等,将耗费时间
    }
    return -1;
}
题目二:

杨氏矩阵查找

解法一:

分治法

以查找数字6为例,因为矩阵的行和列都是递增的,所以整个矩阵的对角线上的数字也是递增的,故我们可以在对角线上进行二分查找,如果要找的数是6介于对角线上相邻的两个数4、10,可以排除掉左上和右下的两个矩形,而在左下和右上的两个矩形继续递归查找,如下图所示:
img

解法二:

定位法:

首先直接定位到最右上角的元素,再配以二分查找,比要找的数(6)大就往左走,比要找数(6)的小就往下走,直到找到要找的数字(6)为止,这个方法的时间复杂度O(m+n)。如下图所示:
img

代码:

#define ROW 4
#define COL 4

bool YoungMatrix(int data[][COL], int serchValue)
{
	int i=0,j=COL-1;
	int var = data[i][j];

	while(true)
	{
		if(var == serchValue)
			return true;
		else if(var < serchValue && i<ROW-1)
			var = data[++i][j];
		else if(var > serchValue && j>0)
			var = data[i][--j];
		else
			return false;
	}
}

举一反三

1、给定 n×n 的实数矩阵,每行和每列都是递增的,求这 n^2 个数的中位数。

2、我们已经知道杨氏矩阵的每行的元素从左到右单调递增,每列的元素从上到下也单调递增的矩阵。那么,如果给定从1-n这n个数,我们可以构成多少个杨氏矩阵呢?

例如n = 4的时候,我们可以构成1行4列的矩阵:

1 2 3 4

2个2行2列的矩阵:

1 2

3 4

1 3

2 4

还有一个4行1列的矩阵

1

2

3

4

因此输出4。


题目三:

数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字

解法一:先排序,快排,遍历,统计次数,输出,时间复杂度O(nlogn + n)。

解法二:排序,输出中间值,时间复杂度O(nlogn)。

解法三:hash表,统计次数,输出,时间复杂度O(1),空间复杂度O(n)。

解法四:

由于题目假定数组中有出现次数超过一半的数字,因此可以通过两个变量,一个是数组中的数字,一个是次数,遍历数组,变量使用的规则是:

  • 如果下一个数字和我们之前保存的数字相同,则次数加1;
  • 如果下一个数字和我们之前保存的数字不同,则次数减1,我们需要保存下一个数字,并把次数重新设为1。

下面,举例:

  • 第一个例子,假定数组为{5, 5, 5, 5, 1}

    不同的相消,相同的累积。遍历到第四个数字时,candidate 是5, nTimes 是4;遍历到第五个数字时,candidate 是5, nTimes 是3;nTimes不为0,那么candidate就是超过半数的。

  • 第二个例子,假定数组为{0, 1, 2, 1, 1}

    开始时,保存candidate是数字0,nTimes为1;遍历到数字1后,与数字0不同,则nTimes减1变为零;接下来,遍历到数字2,2与1不同,candidate保存数字2,且nTimes重新设为1;继续遍历到第4个数字1时,与2不同,nTimes减1为零,同时candidate保存为1;最终遍历到最后一个数字还是1,与我们之前candidate保存的数字1相同,nTimes加1为1。最后返回的是之前保存的candidate为1。

代码实现:

int findNumber(int* data , int n)
{
	int condidate = data[0];
	int nTimes=0;
	for(int i=0;i<n;i++)
	{
		if(condidate == data[i])
		{
			nTimes++;
		}else 
		{
			nTimes--;
		}
		if(nTimes==0)
		{
			condidate = data[i];
			nTimes = 1;
		}
	}
	

	return condidate;
}

举一反三

加强版水王:找出出现次数刚好是一半的数字

分析:我们知道,水王问题:有N个数,其中有一个数出现超过一半,要求在线性时间求出这个数。那么,我的问题是,加强版水王:有N个数,其中有一个数刚好出现一半次数,要求在线性时间内求出这个数。

因为,很明显,如果是刚好出现一半的话,如此例: 0,1,2,1 :

遍历到0时,candidate为0,times为1
遍历到1时,与candidate不同,times减为0
遍历到2时,times为0,则candidate更新为2,times加1
遍历到1时,与candidate不同,则times减为0;我们需要返回所保存candidate(数字2)的下一个数字,即数字1。
思路:

与上题相同,不过这次使用四个变量,由于数组中刚好有数字出现的次数是数组长度一半,因此其他数字的次数都不会比该数字的次数长,所以使用四个变量,两个数字,两个次数,分别记录不同数字的次数,最后选择次数最大者。

代码如下:

int findHalfNumber(int* data, int n)
{
	int condidate1,condidate2;
	int nTime1,nTime2;
	for(int i=nTime1=nTime2=0;i<n;i++)
	{
		if(nTime1==0)
		{
			condidate1=data[i];
			nTime1=1;
		}else if(nTime2==0)
		{
			condidate2=data[i];
			nTime2=1;
		}else
		{
			if(condidate1==data[i])
			{
				nTime1++;
			}else if(condidate2==data[i])
			{
				nTime2++;
			}else
			{
				nTime1--;
				nTime2--;
			}
		}
	}
	return nTime1>nTime2 ? condidate1 : condidate2;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值