找出数组中2个只出现1次的数,其他数都出现2次

问题描述:

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

按位异或相关知识:

按位异或性质:将数转化成2进制,2个数相同异或为0,2数不同异或为1: 0^0=0,1^1=0;0^1=1。(与1异或,得该位元素的反,与0异或,得该位元素)

满足结合律和交换律。

按位异或典型用途:

1、交换两个整数的值而不必用第三个参数
a = 9,  b = 11;
a=a^b; 1001^1011=0010
b=b^a; 1011^0010=1001
a=a^b;  0010^1001=1011

得到:a = 11,b = 9;

2、求一个位串信息的某几位信息的反。如欲求整型变量J的最右4位信息的反,用逻辑异或运算015^J,就能求得J最右4位的信息的反,即原来为1的位,结果是0,原来为0的位,结果是1。

本题思路:

如果一个数组,只有1个元素出现1次,其他元素都出现2次,将所有元素异或,结果即为出现1次的元素(相同元素异或为0,0与元素异或为本身)。

将题目中的数组分成2个分别只含有1个出现1次的元素,其他都是出现2个的元素,即可使用上面的性质求解。

数组分割:

    将所有元素异或,即为2个不同的元素的异或,找到第一个为1的位(不同),然后按照该位为1和为0的分成2个数组,即为只含1个不同元素数组。每个数组中所有元素异或,记得到2个要找的不同的数

代码:

#include <iostream>
using namespace std;

void FindTwoDiffNum(int *arr, int len)
{
	int tmp=0, i=0;
	for (i=0;i<len;i++)
		tmp=tmp^arr[i];//两个不同元素的异或

	int count=0;//移动位数
	while ((tmp & 0x01)==0)//取最后1位
	{
		tmp>>1;//右移1位
		count++;
	}

	//不需要数组分组,只要存储异或结果即可
	int leftResult=0 ,rightResult=0;
	for (i=0;i<len;i++)
	{
		if (((arr[i]>>count) & 0x01)==0)//最后一位相同
			leftResult=leftResult^arr[i];
		else
			rightResult=rightResult^arr[i];
	}
	cout<<leftResult<<' '<<rightResult<<endl;
}

int main()
{
	int arr[]={1,2,3,4,5,3,2,1};
	FindTwoDiffNum(arr,8);

	int arr2[]={1,2,3,8,7,3,2,1};
	FindTwoDiffNum(arr2,8);

	system("pause");
	return 0;
}




点赞