`
xitonga
  • 浏览: 579500 次
文章分类
社区版块
存档分类
最新评论

数组中只出现一次的数字

 
阅读更多
/***********************************************************************
题目:一个整型数组除了两个数字之外,其他的数字都出现了两次。请写程序找出
这两个只出现一次的数字。要求时间复杂度是O(N),空间复杂度为O(1)。
***********************************************************************/
/*
解题思路:
由于其他数字都出现了两次,那么最终得到的结果就是两个只出现一次的数字的
异或结果。因为其他数字都出现了两次,在异或中全部抵消了。由于这两个数字
肯定不一样,那么异或的结果肯定不为0,也就是说在这个结果数字的二进制表示
中至少就有一位为1。我们在结果数字中找到第一个为1的位,记为第n位。现在我们
以第n位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数
字的第n位都是1,而第二个子数组中每个数字的第n为都是0。由于我们分组的标准
是数字中的某一位是1还是0,那么出现了两次的数字肯定被分配到同一个数组。因
为两个相同的数字的任意一位都是相同的,我们不可能把两个相同的数字分配到两
个子数组中去,于是我们已经把原数组分成了两个子数组,每个字数组都包含一个
只出现一次的数字,而其他数字都出现了两次。我们已经知道如何在数组中找出
唯一一个只出现一次的数字,因此到此为止所有的问题都已经解决了。
举个例子:
假设输入数组{2,4,,6,3,2,5,5}。当我们依次对数组中的每一个数字做异或运算之后,
得到的结果用二进制表示是0010。异或得到结果中的倒数第二位是1,于是我们根据数
字的倒数第二位是不是1分成两个数组。第一个子数组{2,3,6,3,2}中所有数字的倒数
第二位都是0。接下来只要分别对这两个子数组求异或,就能找出第一个子数组中只
出现一次的数字是6,而第二个子数组中只出现一次的数字是4。
*/
#include<stdio.h>
unsigned int findFirstBitIs1(int num);
bool IsBit1(int num, unsigned int indexBit);
void findNumAppearOnce(int* data,int length,int* num1,int* num2)
{
	if(data == NULL || length<2)
		return;

	int resultExclusiveOR = 0;
	for(int i=0; i<length; ++i)
		resultExclusiveOR ^= data[i];

	unsigned int indexOf1 = findFirstBitIs1(resultExclusiveOR);

	*num1 = *num2 = 0;
	for(int j=0; j<length; ++j)
	{
		if(IsBit1(data[j],indexOf1))
			*num1 ^= data[j];
		else
			*num2 ^= data[j];
	}
}
//找到所有数字异或后的结果,最先出现1的位置
unsigned int findFirstBitIs1(int num)
{
	int indexBit = 0;
	while(((num & 1) == 0) && (indexBit < 8 * sizeof(int)))
	{
		num = num>>1;
		++indexBit;
	}
	return indexBit;
}
//判断数字num上第indexBit位是不是为1。
bool IsBit1(int num, unsigned int indexBit)
{
	num = num >> indexBit;
	return (num & 1);
}

void test()
{
	const int length = 8;
	int arr[length] = {2,4,3,6,3,2,5,5};
	int num1 = 0;
	int num2 = 0;
	findNumAppearOnce(arr,length,&num1,&num2);
	printf("%d\t%d\n",num1,num2);
}
int main()
{
	test();
	return 0;
}
==参考剑指offer
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics