剑指offer面试题:数组中只出现一次的数字

题目:一个整型数组里除了两个数字之外,其他的数字都出现两次。请找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度O(1)。

看到这个问题,我们首先应该想到另一个问题,如果数组中只有一个数字出现一次,怎么找到它呢?

由此引出异或运算:任何一个数字异或它自己都等于0.

所以如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字,其它成对出现的已经全部在异或中抵消了。

现在回到原问题,若把数组分成两个数组,每个数组包含一个只出现一次的数字,其它数字出现两次,然后分别在对两个数组用前面方法求异或,就可以得到正确结果,以下为代码实现:

#include <stdio.h>
#include <stdlib.h>
void FindNum_one(int arr[],int lenth,int *p1,int *p2)
{
	int num=0;//用于存放数组数字依次异或后得到的结果
	int bit=0;//用于判断num二进制最右边是1的位
	int i=0;
	if((arr==NULL)&&(lenth<2))//若数组为空或长度为1则直接返回
	{
		return;
	}
	for(i=0;i<lenth;i++)//从头到尾依次异或数组中数字
	{
		num^=arr[i];
	}
	while(((num&1)==0)&&(bit<32))//找出整数num二进制中表示最右边1的位
	{
		num=num>>1;
		bit++;
	}
	for(i=0;i<lenth;i++)//划分数组并分别依次异或每个数组数据,得出结果*p1,*p2
	{
		if((arr[i]>>bit)&1==1)
		{
			*p1^=arr[i];
		}
		else
		{
			*p2^=arr[i];
		}
	}
}
int main()
{
	int arr[]={2,4,3,6,3,2,5,5};
	int num1=0;
	int num2=0;
	int lenth=sizeof(arr)/sizeof(arr[0]);
	FindNum_one(arr,lenth,&num1,&num2);
	printf("两个只出现一次的数字是:\n%d  %d\n",num1,num2);
	system("pause");
	return 0;
}


以上的过程就是对数组每一个数做异或运算后,得到结果0010,异或得到结果的倒数第二位为1,于是我们根据数字倒数第二位是不是1分成两个数组,第一个倒数第二位是1的数组{2,3,6,3,2},第二个倒数第二位为0的数组{4,5,5},然后分别异或,得出结果6,4.

你可能感兴趣的:(剑指offer面试题:数组中只出现一次的数字)