【3】数组中只出现一次的数字

题目:输入一个整型数组,数组里除了两个数出现一次之外,其它所有数字出现的次数都是2次,求这两个数字。要求时间复杂度为O(n),空间复杂度为O(1)


1 题目要求时间复杂度为O(n)并且空间复杂度为O(1)。这个时候朴素的方法利用数字来记录出现次数的方案都是不行的。

2 根据题目的特点,只有两个数出现一次,其它的所有数据都是出现2次。如果这两个数是a和b,那么对这个数组异或的结果就是a^b。现在我们就是要考虑怎么把数组分成两部分,一部分含有a,一部分含有b,则每部分异或的结果即为两个数a和b的值

3 因为a肯定不等于b,所以a^b的结果肯定不会等于0,那么我们可以就去这个异或结果中最右边的第一个1的位置,根据这个位置来划分这个数组,这个位置是1的位一部分,不是1的分为一部分。

4 例如数组{2,4,3,6,3,2,5,5},数组异或的结果为2,二进制位0010最右边1的位置为第二位。则我们把数组分成两部分{2,3,6,3,2}中每个数的二进制最右边第二位为1,剩下一部分{4,5,5}中每个数二进制最右边第二位为0。

5 求出两部分之后我们就可以直接对每部分求异或即可求出两个数的值


//找到两个只出现一次的数
void FindNumAppearOnce(int *arrNum, int n){
	//空指针和个数小于2都是不合法的数据
	if(arrNum == NULL || n < 2){
	    return;
	}
	//先求出总的异或的值
	int sum = 0;
	for(int i = 0; i < n; i++){
	    sum ^= arrNum[i];
	}
	//找到sum的右边第一个1的位置
	int pos = 0;
	while((sum & 1) != 1 && (pos <= 32)){
	    pos++;
		sum >>= 1;
	}
	//没有找出第一个1的位置
	if((pos == 0) || (pos > 32)){
	    return;
	}
	//定义两个数为
	int numOne = 0;
	int numTwo = 0;
	//枚举求出
	int num = 1<<pos;
	cout<<num<<endl;
	for(int i = 0; i < n; i++){
		if((arrNum[i]&num) != 0){
		    numOne ^= arrNum[i];
		}
		else{
		    numTwo ^= arrNum[i];
		}
	}
	cout<<numOne<<" "<<numTwo<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值