分析:
假设只出现一次的三个数字是a,b,c
1. 首先遍历数组,xor代表所有值的异或和,最终,xor = a^b^c;
2. 证明xor与a,b,c值得都不一样。如果xor与a值一样,那么xor = a^b^c = a, 也就是b^c=0,也就是b等于c,这与题目矛盾,所以xor与a,b,c的值都不一样,也就是xor^a,xor^b,xor^c都不为0;
3. 函数find_1bit()(以下简称f())用于查询某个数中从右边扫描比特1第一次出现的位置,比如6,二进制为0110,通过f()返回0010;
4. 证明f(xor^a)^f(xor^b)^f(xor^c)的值不为0。因为f(xor^a)^f(xor^b)的值要不为0,也不出现两个比特1,而f(xor^c)只有一个比特1,二者肯定不相等,所以f(xor^a)^f(xor^b)^f(xor^c)的值不为0;
5. f(xor^a)^f(xor^b)^f(xor^c)的值至少有一位为1。假设从右边扫描第一个1出现的位置在m位,那么f(xor^a)、f(xor^b)、f(xor^c)在m位的数值要不全为1,要不只有一个为1,另两个为0;
6. 证明f(xor^a)、f(xor^b)、f(xor^c)在m位的数值不全为1。假设全为1,那么在m位上,a,b,c的值相同,与xor相反。如果a、b、c值在m位上全为0,那么xor=a^b^c=0,与假设矛盾。如果a、b、c值在m位上全为1,那么xor=a^b^c=1,也与假设矛盾。所以f(xor^a)、f(xor^b)、f(xor^c)在m位的数值不全为1,只有一个为1,另两个全为0.根据这一位的1,我们可以分为两组,分别进行求解;
#include <stdio.h>
int find_1bit(int n)
{
return n&~(n-1);
}
void get_two(int a[], int n, int *num1, int *num2)
{
int xor;
int i;
for(i=0;i<n;i++)
xor ^= a[i];
xor = find_1bit(xor);
for(i=0;i<n;i++)
if(a[i]&xor)
*num1 ^= a[i];
else
*num2 ^= a[i];
}
void get_three(int a[], int n, int *num1, int *num2, int *num3)
{
int xor = 0;
int f = 0;
int i;
int temp;
for(i=0;i<n;i++)
xor ^= a[i];
for(i=0;i<n;i++)
f ^= find_1bit(xor ^ a[i]);
f = find_1bit(f);
for(i=0;i<n;i++)
if(find_1bit(xor^a[i]) == f)
*num1 ^= a[i];
for(i=0;i<n;i++)
if(a[i] == *num1)
{
temp = a[i];
a[i] = a[n-1];
a[n-1] = temp;
}
get_two(a,n-1,num2,num3);
}
int main()
{
int a[] = {2,2,3,3,4,4,5,6,7};
int num1 =0,num2 = 0,num3 = 0;
int i;
printf("原数组为:\n");
for(i=0;i<9;i++)
printf("%d\t",a[i]);
printf("\n");
get_three(a,9,&num1,&num2,&num3);
printf("只出现1次的三个数字:\n");
printf("%d\t%d\t%d\t",num1,num2,num3);
printf("\n");
return 0;
}