一个数组中除了三个数字之外,其余数字都出现了两次,找出这三个数字

分析:

假设只出现一次的三个数字是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;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值