C++面试题之数组中的重复数字

题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

解决方案

1、最简单的办法就是把输入的数组排序,然后从头到尾扫描数组很容易地找出重复的数字。时间复杂度为O(nlogn)。

2、利用哈希表,从头到尾按顺序扫描数组的每个数字,每扫描到一个数字,都可以用O(1)的时间来判断哈希表里是否包含该数字。如果不包含,就把它加入,如果包含,就找到了一个重复的数字。时间复杂度为O(n),但需要额外的一个O(n)的哈希表。

3、利用类似于桶排序的原理,数组中的所有数字都为0到n-1,可以把这些数字当做数组下标,数值用来统计个数,即i为下标,a[i]为个数,如果a[i]>1,则i为相应的重复数字。时间复杂度为O(n),空间复杂度为O(n)。

//a为该数组 length为数组长度 result为找到的一个重复数字
bool fuction1(int a[], int length, int *result)
{
	/*错误判断省略*/
	int map[255] = {0};
	for (int i = 0; i < length; i++)
	{
		map[a[i]]++;
	}
	for (int i = 0; i < length; i++)
	{
		if (map[i] > 1)
		{
			*result = i;
			return true;
		}
	}
	return false;
}

4、最好的方法当然最后出场了。时间复杂度O(n),空间复杂度O(1)。先上代码。

bool fuction2(int a[],int length,int *result)
{
	/*错误判断省略*/
	for (int i = 0; i < length; i++)
	{
		while (true)
		{
			if (a[i] == i)
			{
				break;
			}
			if (a[i] == a[a[i]])
			{
				*result = a[i];
				return true;
			}
			int t = a[a[i]];
			a[a[i]] = a[i];
			a[i] = t;
		}
	}
	return false;
}

注意数组长度为n,且数值都在0到n-1,如果没有重复,排序完后数字i应该出现在下标为i的地方,即数组第0个元素应为0,第1个元素应为1……按照这个顺序把该数组进行排序,一直排下去,如果两个要交换的值是一样的,就代表这个值是重复的。虽然是两重循环,但是每个元素最多换两次位置就能找到属于自己的位置,因此时间复杂度为O(n)。

5、看到的某个大佬的操作,真的6p。

int find_dup(int numbers[], int length) 
{
	for (int i = 0; i<length; i++) {
		int index = numbers[i];
		if (index >= length) {
			index -= length;
		}
		if (numbers[index] >= length) {
			return index;
		}
		numbers[index] = numbers[index] + length;
	}
	return -1;
}

时间复杂度O(n),空间复杂度O(1)。

主要思想就是如果一个长度为n,值为0到n-1,且没有重复的数组,i从0到n-1,对应的a[0]到a[n-1]不会指向同一个a[i]两次。这里,对于i,先让a[a[i]]加上一数组长度length,如果后面这个i再次出现,那么a[a[i]]必定比length大,那么i就位重复的数。

缺点:对原数组数值进行了更改,本题的核心是查找问题,参数类型很有可能为const,这样做有偷鸡的意思。不过真的很难想到。

猜你喜欢

转载自blog.csdn.net/qq_32957239/article/details/80500183