剑指offer:数组中的重复数字

题目:数组中的重复数字。在一个长度为n的数组里所有的数字都在0~n-1范围,数组中某些数字是重复的,但是不知道有几个数字重复了,请找出数组中任意一个重复的数字。例如:长度为7的数组[2,3,1,2,5,3],重复的数字是2或者3。

分析:

方法(1):用两层for循环,拿着每一个数据与剩下的每一个比较,看看有没有再次出现时间复杂度O(n*n)(参数中ret是返回型参数,带回那个找找到的重复数)。
 

bool find_duplicate1(int arr[], int len, int* ret)
{
	for (int i = 0; i < len; i++)
	{
		//j得从i的下一个位置开始
		for (int j = i + 1; j < len; j++)
		{
			if (arr[i] == arr[j])
			{
				*ret = arr[i];
				return true;
			}
		}
	}
	//来到这说明没找到
	return false;
}

方法(2),先排序(我们这采用快速排序),然后找出相邻的相同的两个元素快速排序调用的函数(升序)。时间复杂度O(nlogn)

int compare(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;
}
bool find_duplicate2(int arr[], int len, int* ret)
{
	//调用快速排序
	qsort(arr, len, sizeof(arr[0]), compare);
 
	//找相邻并且相同的元素
	for (int i = 0; i < len-1; i++)
	{
		if (arr[i] == arr[i + 1])
		{
			*ret = arr[i];
			return true;
		}
	}
	//来到这,说明没找到
	return false;
}

方法(3):哈希法。建立一个大小为n的count数组,从头扫描原数组中的每一个元素,判断在count数组中以该元素为下标的统计值是否为1,如果已经是1了,那么找到这个重复元素了,如果不是1,则将其置1,然后继续下一个元素...时间复杂度O(n),空间复杂度O(n)

bool find_duplicate3(int arr[], int len, int* ret)
{
	int* count = (int*)malloc(sizeof(int)*len);
 
	for (int i = 0; i < len; i++)
	{
		if (count[arr[i]] == 1)
		{
			*ret = arr[i];
			return true;
		}
		else
		{
			count[arr[i]] = 1;
		}
	}
	//来到这,说明没找到
	return false;
}

方法(4):由于数组大小为n,则下标为0~n-1,又已知数组大小也是0~n-1,那么我们知道,如果说元素没有重复的话,排好序后元素i就应该在下标为i的位置上,但是现在元素有重复的。那么我们可以从头开始依次扫描原数组中的元素,如果该元素等于其下标值,那么就判断下一个元素,如果不相等,那么该元素要么大于该下标,要么小于该下标,此时判断该元素是不是等于以该元素为下标的对应元素,如果是那么就找到重复的这个元素了,如果不是那么就将该元素与以该元素为下标的位置上(这个过程起始是逐渐将每个元素都放在以它自己为下标的位置上,即元素与下标一一对应,如果遇到的元素是符合这种一一对应的,就看下一个,如果不对应,那就看看之前出现过没有,没有出现就把它放在符合一一对应的位置上)时间复杂度O(n),空间复杂度O(1),每个元素最多2次就可以放在它应该放的位置。
 

bool find_duplicate4(int arr[], int len, int* ret)
{
	//参数合法性检测
	if (arr == NULL || len < 0)
	{
		return false;
	}
	for (int i = 0; i < len; i++)
	{
		if (arr[i]<0 || arr[i]>len - 1)
		{
			return false;
		}
	}
 
	for (int i = 0; i < len; i++)
	{
		// 只要该元素与它的下标不一一对应,就一直交换
		//如果压根就没有与该下标相同的元素也没有关系
		//因为交换的过程中不断让其他元素与自己的下标一一对应
		//既然该元素与它的下标对应,那么就说明它拿的是别人的
		//下标,当别人慢慢一一对应后,我们会通过该元素和该元素
		//作为下标的元素进行比较,此时别人一一对应了,通过
		//比较就会找到这个重复元素了
		while (arr[i] != i)
		{
			if (arr[arr[i]] == arr[i])
			{
				*ret = arr[i];
				return true;
			}
			else//将arr[i]放在与其对应下标的位置
			{
				int tmp = arr[i];
				arr[i] = arr[tmp];
				arr[tmp] = tmp;
			}
		}
	}
	//来到这,说明没有
	return false;
}

猜你喜欢

转载自blog.csdn.net/zy20150613/article/details/89883373