# 面试题：找出数组中只出现一次的2个数（异或的巧妙应用）（出现3次）

```///////////////////////////////////////////////////////////////////////
// Find two numbers which only appear once in an array
// Input: data - an array contains two number appearing exactly once,
//               while others appearing exactly twice
//        length - the length of data
// Output: num1 - the first number appearing once in data
//         num2 - the second number appearing once in data
///////////////////////////////////////////////////////////////////////
void FindNumsAppearOnce(int data[], int length, int &num1, int &num2)
{
if (length < 2)
return;

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

// get index of the first bit, which is 1 in resultExclusiveOR
unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);

num1 = num2 = 0;
for (int j = 0; j < length; ++ j)
{
// divide the numbers in data into two groups,
// the indexOf1 bit of numbers in the first group is 1,
// while in the second group is 0
if(IsBit1(data[j], indexOf1))
num1 ^= data[j];
else
num2 ^= data[j];
}
}

///////////////////////////////////////////////////////////////////////
// Find the index of first bit which is 1 in num (assuming not 0)
///////////////////////////////////////////////////////////////////////
unsigned int FindFirstBitIs1(int num)
{
int indexBit = 0;
while (((num & 1) == 0) && (indexBit < 32))
{
num = num >> 1;
++ indexBit;
}

return indexBit;
}

///////////////////////////////////////////////////////////////////////
// Is the indexBit bit of num 1?
///////////////////////////////////////////////////////////////////////
bool IsBit1(int num, unsigned int indexBit)
{
num = num >> indexBit;

return (num & 1);
}
```

01 10 11 11 100 100  异或结果：11

01 11 11 异或num1=01

10 100 100 异或num2=10.

求最低位1：

int get_first_bit(int num)
{
return num&~(num – 1);
}

（基本跟上面的题一样）

#### 获取计算出的异或值的1所在的位置，并继续异或

01 11                10    100

11                     100

m = ( 1 + 2 + …+ 1000) – (998 个的和) x + y

n = ( 1 * 2 * …. * 1000) / ( 998 个的积)x * y

x =  sqart( pow( m , 2 ) / 4 – n ) + m /2

y = m – x

```double x = 3 ;
double y = 39 ;

double m = x + y ;
double n = x * y ;

x = Math.sqrt( m * m / 4d - n ) + m / 2 ;
y = m - x ;
System.out.println( x );
System.out.println( y );```

### 找数字分析

#### 分析

• A xor A = 0

• A xor 0 = A

• 采用hashmap，时间复杂度O(n)，空间复杂度O(n)

• 对数组A进行排序，然后在遍历一次，时间复杂度O(nlogn)，空间复杂度O(1) 这个方法还可以。

• 如果某个特定位上的1加起来，可以被3整除，说明对应x的那位是0，因为如果是1，不可能被3整除

• 如果某个特定位上的1加起来，不可以被3整除，说明对应x的那位是1

```#include<iostream>
using namespace std;

void set(int& a,int i) { a |= (1<< (i & 0x1F));}
void clr(int& a,int i) { a &= ~(1<<(i & 0x1f));}

//除了某一个数字x之外，其他数字都出现了三次，而x出现了一次

void find(int a[],int n)
{
int m[32];
for(int i=0;i<32;i++)
m[i]=0;

for(int i=0;i<32;i++)
{
for(int j=0;j<n;j++)
{
int bit=a[j]&1;//&相当于mod 2
m[i]+=bit;
a[j] >>=1;
}
}
/*
for(int i=0;i<32;i++)
cout<<m[i]<<ends;
cout<<endl;
*/
int result=0;
for(int i=0;i<32;i++)
{
if(m[i]%3!=0)
set(result,i);
}
cout<<"结果为"<<result<<endl;

}
int main()
{
int a[]={1,2,2,2,3,3,3};
int n=sizeof(a)/sizeof(a[0]);
find(a,n);
/*
int b=2;
set(b,0);
clr(b,1);
cout<<b<<endl;
*/

}```

```void set(int& a,int i) { a |= (1<< (i & 0x1F));} 把a第i位置为1；
void clr(int& a,int i) { a &= ~(1<<(i & 0x1f));} 把a的第i位清0.参考了以前的位图排序:http://www.cnblogs.com/youxin/p/3304667.html)```

### 题目：一个数组中有三个数字a、b、c只出现一次，其他数字都出现了两次。请找出三个只出现一次的数字。

（与最前面的一题不同，前面是2个不同，现在是3个）

（要求空间为O(1)，所以用hash判断是否重复这种方法不管用了）

```void getThreeUnique(vector<int>& numbers, vector<int>& unique)
{
if(numbers.size() < 3)
return;

int xorResult = 0;
vector<int>::iterator iter = numbers.begin();
for(; iter != numbers.end(); ++iter)
xorResult ^= *iter;

int flags = 0;
for(iter = numbers.begin(); iter != numbers.end(); ++iter)
flags ^= lastBitOf1(xorResult ^ *iter);
flags = lastBitOf1(flags);

// get the first unique number
int first = 0;
for(iter = numbers.begin(); iter != numbers.end(); ++iter)
{
if(lastBitOf1(*iter ^ xorResult) == flags)
first ^= *iter;
}
unique.push_back(first);

// move the first unique number to the end of array
for(iter = numbers.begin(); iter != numbers.end(); ++iter)
{
if(*iter == first)
{
swap(*iter, *(numbers.end() - 1));
break;
}
}

// get the second and third unique numbers
getTwoUnique(numbers.begin(), numbers.end() - 1, unique);
}

int lastBitOf1(int number)
{
return number & ~(number - 1);
}

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);
}```

```#include<stdio.h>
int get_first_bit(int num)
{
return num&~(num-1);
}
void get_two_unique_num(int *a,int n,int *num1,int *num2)
{
int result_code=0;
for(int i=0;i<n;i++)
result_code^=a[i];
int diff=get_first_bit(result_code);
*num1=0;
*num2=0;
for(i=0;i<n;i++)
{
if(a[i]&diff)
{
(*num1)^=a[i];
}
else
{
(*num2)^=a[i];
}
}
}
void get_three_unique_num(int *a,int n,int *num1,int *num2,int *num3)
{
int result_code=0;
for(int i=0;i<n;i++)
result_code^=a[i];
int flag=0;
for(i=0;i<n;i++)
flag^=get_first_bit(result_code^a[i]);
flag=get_first_bit(flag);
*num1=0;
for(i=0;i<n;i++)
{
if(get_first_bit(result_code^a[i])==flag)
{
(*num1)^=a[i];
}
}
for(i=0;i<n;i++)
{
if(a[i]==(*num1))
{
int temp=a[i];
a[i]=a[n-1];
a[n-1]=temp;
break;
}
}
get_two_unique_num(a,n-1,num2,num3);
}
void main()
{
int a[]={2,2,4,4,6,6,3,5,7};
int num1,num2,num3;
get_three_unique_num(a,sizeof(a)/sizeof(int),&num1,&num2,&num3);
printf("%d\t%d\t%d\n",num1,num2,num3);
}  ```

http://my.oschina.net/u/1455799/blog/262854

原文作者：算法小白
原文地址: https://www.cnblogs.com/youxin/p/3349834.html
本文转自网络文章，转载此文章仅为分享知识，如有侵权，请联系博主进行删除。