剑指offer--------找出数组中重复的数字

问题:在一个长度为n的数组里的所有数字都在0-n~1的范围里,不知道重复的数字,也不知道每个重复数字重复几次,找出数组中所有重复的数字,如输入{2,3,1,0,2,5,3},则应输出{2,3}。

要求1:能改变数组中的数字

思路1:将数组排序,然后遍历数组,找出重复的数字。时间复杂度o(nlogn),空间复杂度o(1)。

思路1的实现:

vector<int> FindDuplicationNum(vector<int> &TestData)
{
	vector<int> res;
	sort(TestData.begin(),TestData.end());
	int i = 0;
	int j = 1;
	int flag = -1;      //判断当前重复数字是否需要存入结果数组中。
	for (j; j < TestData.size();j++)
	{
		if (TestData[i] != TestData[j]) i = j;
		else
		{
			if (flag != i)
			{
				res.push_back(TestData[i]);
				flag = i; 
			}	
		}
	}
	return res;
}

思路2:因数组中的数字都在0~n-1的范围内,所以若数组中没有重复的数字,则排序后数字i将出现在下标为i的位置,而有重复的数字时,多个位置出现同一数字。因此可以遍历该数组,当扫描到下标为i的数字时,首先比较这个数字(用m表示)与i是否相等,若相等,则接着扫描下一个数字,若不相等,则比较m与第m个位置上的数字n是否相等,若相等,则m为重复的数字(第i个位置与第m个位置的值相等),若不等,则交换m与n的值,直到找到重复数字或下标为i的数字与i相等,然后扫描下一个数字。时间复杂度o(n),空间复杂度o(1)。

思路2的实现

vector<int> FindDuplicationNum(vector<int> &TestData)
{
	vector<int> res;
	//合法输入验证
	if (TestData.size() == 0) return res;
	for (int i = 0; i < TestData.size();i++)
	{
		if (TestData[i] < 0 || TestData[i] > TestData.size() - 1)return res;
	}
	for (int i = 0; i < TestData.size(); i++)
	{
		while (i != TestData[i])
		{
			if (TestData[i] == TestData[TestData[i]])
			{
				res.push_back(TestData[i]);
				break;
			}
			else
			{
				int temp = TestData[i];
				TestData[i] = TestData[TestData[i]];
				TestData[temp] = temp;
			}
		}
	}
	return res;
}

要求2:不能改变数组

思路1:遍历数组,统计每个数字出现的次数,将结果存入map中;遍历map,找出重复的数字。时间复杂度o(n),空间复杂度o(n)。

思路1 的实现

vector<int> FindDuplicationNum(vector<int> &TestData)
{
	map<int, int>count;
	vector<int> res;
	for (int i = 0; i < TestData.size(); i++)
	{
		count[TestData[i]]++;
	}
	auto i = count.begin();
	while (i != count.end())
	{
		if (i->second > 1)
		{
			res.push_back(i->first);
		}
		i++;
	}
	return res;
}

思路2:把0~n-1的数字从中间的数字m分为两部分,前一部分为0~m,后一部分为m+1~n-1,如果0~m的数字的数目超过m+1个,则该部分一定含有重复数字,反之,另一半的区间里一定含有重复数字。然后继续把包含有重复数字的区间一分为二,直到找到一个重复数字为止。

思路2的实现

int countRange(vector<int> &TestData, int start, int middle)     //统计当前部分各数字在数组中出现的次数。
{
	int count = 0;
	for (int i = 0; i < TestData.size();i++)
	{
		if (TestData[i] >= start && TestData[i] <= middle) count++;
	}
	return count;
}
int FindDuplicationNum(vector<int> &TestData)
{
	int start = 0;
	int end = TestData.size() - 1;
	while (start <= end)
	{
		int middle = start + (end - start) / 2;
		int count = countRange(TestData, start, middle);
		if (end == start)
		{
			if (count > 1)return start;
			else break;
		}
		if (count > middle- start + 1)
		{
			end = middle;
		}
		else start = middle + 1;
	}
	return -1;
}
在该思路的中,调用countRange函数o(logn)次,每次需要o(n)的时间,因此总的时间复杂度为o(nlogn),空间复杂度为o(1)。但值得注意的是,该算法中,不能保证找到所有重复的数字。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值