现在的位置: 首页 > 综合 > 正文

第三十三题 输出容器中3个不同的数

2018年04月13日 ⁄ 综合 ⁄ 共 2692字 ⁄ 字号 评论关闭

题目:一个数组中有三个数字abc只出现一次,其他数字都出现了两次。请找出三个只出现一次的数字。

思路:如果我们把数组中所有数字都异或起来,那最终的结果(记为x)就是abc三个数字的异或结果(x=a^b^c)。其他出现了两次的数字在异或运算中相互抵消了。

我们可以证明异或的结果x不可能是abc三个互不相同的数字中的任何一个。我们用反证法证明。假设x等于abc中的某一个。比如x等于a,也就是a=a^b^c。因此b^c等于0,即b等于c。这与abc是三个互不相同的三个数相矛盾。

由于xabc都各不相同,因此x^ax^bx^c都不等于0

我们定义一个函数f(n),它的结果是保留数字n的二进制表示中的最后一位1,而把其他所有位都变成0。比如十进制6表示成二进制是0110,因此f(6)的结果为2(二进制为0010)。f(x^a)f(x^b)f(x^c)的结果均不等于0

接着我们考虑f(x^a)^f(x^b)^f(x^c)的结果。由于对于非0nf(n)的结果的二进制表示中只有一个数位是1,因此f(x^a)^f(x^b)^f(x^c)的结果肯定不为0。这是因为对于任意三个非零的数ijkf(i)^f(j)的结果要么为0,要么结果的二进制结果中有两个1。不管是那种情况,f(i)^f(j)都不可能等于f(k),因为f(k)不等于0,并且结果的二进制中只有一位是1

于是f(x^a)^f(x^b)^f(x^c)的结果的二进制中至少有一位是1。假设最后一位是1的位是第m位。那么x^ax^bx^c的结果中,有一个或者三个数字的第m位是1

接下来我们证明x^ax^bx^c的三个结果第m位不可能都是1。还是用反证法证明。如果x^ax^bx^c的第m位都是1,那么abc三个数字的第m位和x的第m位都相反,因此abc三个数字的第m位相同。如果abc三个数字的第m位都是0x=a^b^c结果的第m位是0。由于xa两个数字的第m位都是0x^a结果的第m位应该是0。同理可以证明x^bx^cm位都是0。这与我们的假设矛盾。如果abc三个数字的第m位都是1x=a^b^c结果的第m位是1。由于xa两个数字的第m位都是1x^a结果的第m位应该是0。同理可以证明x^bx^cm位都是0。这还是与我们的假设矛盾。

因此x^ax^bx^c三个数字中,只有一个数字的第m位是1。于是我们找到了能够区分abc三个数字的标准。这三个数字中,只有一个数字满足这个标准,而另外两个数字不满足。一旦这个满足标准数字找出来之后,另外两个数字也就可以找出来了。

#include <iostream>
#include <vector>
using namespace std;
//得到输入数据的只有最后一个1的数
int lastBitOf1(int number)
{
	return number & ~(number - 1);
}
void getTwoUnique(vector<int>::iterator begin, vector<int>::iterator end, vector<int>& unique);
void getThreeUnique(vector<int>& numbers, vector<int>& unique)
{
	if(numbers.size() < 3)
		return;
	int index = 0;
	vector<int>::iterator iter = numbers.begin();
	//所有数异或过后的结果保存在index中
	for(; iter != numbers.end(); ++iter)
		index ^= *iter;
	//将index分别与所有的数异或得到flag
	int flags = 0;
	for(iter = numbers.begin(); iter != numbers.end(); ++iter)
		flags ^= lastBitOf1(index ^ *iter);
	flags = lastBitOf1(flags);//此时flag必然不为0,,可以通过flag推出与flag同样位置为1的那个不同的数
	int first = 0;
	for(iter = numbers.begin(); iter != numbers.end(); ++iter)
	{
		if(lastBitOf1(*iter ^ index) == flags)
			first ^= *iter;
	}
	unique.push_back(first);
	for(iter = numbers.begin(); iter != numbers.end(); ++iter)
	{
		if(*iter == first)
		{
			swap(*iter, *(numbers.end() - 1));
			break;
		}
	}
	getTwoUnique(numbers.begin(), numbers.end() - 1, unique);
}


//处理只有2个数不同时
void getTwoUnique(vector<int>::iterator begin, vector<int>::iterator end, vector<int>& unique)
{
	int xorResult = 0;
	for(vector<int>::iterator iter = begin; iter != end; ++iter)
		xorResult ^= *iter;
	int diff = lastBitOf1(xorResult);
	int first = 0;
	int second = 0;
	for(vector<int>::iterator iter = begin; iter != end; ++iter)
	{
		if(diff & *iter)
			first ^= *iter;
		else
			second ^= *iter;
	}
	unique.push_back(first);
	unique.push_back(second);
}
int main()
{
	vector<int> vec1;
	vector<int> vec2;
	vec1.push_back(1);
	vec1.push_back(3);
	vec1.push_back(4);
	vec1.push_back(2);
	vec1.push_back(3);
	vec1.push_back(1);
	vec1.push_back(4);
	vec1.push_back(5);
	vec1.push_back(7);
	getThreeUnique(vec1,vec2);
	for (auto it=vec2.begin();it!=vec2.end();++it)
	{
		cout<<*it<<endl;
	}
	return 0;
}


抱歉!评论已关闭.