剑指Offer系列-面试题40:数组中只出现一次的数字

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

思路:利用异或的特点,一个数的二进制异或自己,结果为0,既然数组中只有两个数字出现一次,其他出现两次,那么首先考虑这样一个问题:一个数组中,只有一个数字出现一次,其他数字出现两次,那么只需要全部异或,既然一个数异或自己为0,而0异或任何数都为这个数本身,那么全部异或后,最终的结果就是要找的数。

现在考虑本题的情况,既然有两个数只出现一次,那么如果我们把数组分为两部分,一部分中只包含一个只出现一次的数字,那么问题就迎刃而解了。这种情况下,我们把整个数组异或一遍,会得到一个数字,由于只出现一次的数字有两个,那么异或一遍等于是将这两个数字异或,如6和4,异或是0110^0100=0010,即至少有一位为1,不可能全为0,那么我们就找到了他们的差异,从右往左第一个为1的位,可以当做他们的特征,即6的二进制倒数第二位是1,这样就可以将整个数组分为两部分了,只要二进制倒数第二位是1的数字,我们把他分到6所在的那一个数组,不是的话分到4所在的那个数组,这样就找到了了两个数。

见代码,有注释。

代码:

public void FindNumsAppearOnce(int [] array, int num1[] , int num2[]) {
    if(array == null || array.length < 2) {
    	return;
    }
    int result = 0;
    for (int i : array) {
		result ^= i;
	}
    int indexOf1 = FindFirstBitIs1(result);
    num1[0] = 0;
    num2[0] = 0;
    for (int i : array) {
		if (isBit1(i, indexOf1)) { // 如果属于第一个数组
			num1[0] ^= i;
		} else {
			num2[0] ^= i;
		}
	}
}
// 寻找从右往左的第一个为1的位,即特征位
private int FindFirstBitIs1(int result) {
	int index = 0;
	while ((result & 1) == 0 && index < 8 * 4) {
		result = result >>> 1;
    	index++;
	}
	return index;
}

// 判断一个数字的二进制从右到左数第n位是否为1,用来分两个数组
private boolean isBit1(int num, int indexBit) {
	num = num >>> indexBit;
	return ((num & 1) == 0) ? false : true;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值