剑指offer之数组中数字出现的次数

1. 题目

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

2. 思路

首先,可以想一下,如果数组中只有一个数字只出现了一次,其他数字都出现了两次,怎么找出这个数字呢?根据这个问题可以想到异或的一个性质:加任何一个数字异或它自己都等于0。也就是说,如果从头到尾异或每个数字,那么最终的结果就是那个只出现了一次的数字,因为那些成对出现的数字都在异或中抵消了。

根据上面的思路,我们异或数组中的所有数字,这里可以得到一个不为 0 的数字,这个数字是数组中两个只出现一次数字的异或结果。因为这个结果不为 0,因此我们可以从右向左找出这个数字二进制第一个不为 0 的数字,根据这一位将数组分为两个子数组(长度为 2),这一位为 1 的数字放在第一个子数组中,这一位为 0 的数字放在第二个子数组中。对这两个子数组进行异或操作,即可得到最终的结果。

3. 代码

public class F56FindNumsAppearOnce {
    public void solution(int[] data,int[] result){
	if(data==null || data.length<2)
	    return ;
	int resultExclusiveOR = 0;
	// 将数组中所有数字都进行异或操作
	for(int i=0;i<data.length;i++)
	    resultExclusiveOR ^= data[i]; 
	// 找出异或操作结果二进制第一个不为 0 的位置
	int indexOf1 = findFirstBitsIs1(resultExclusiveOR);
	// 根据 indexOf1 位置上是否 1 分为两个数组
	for(int i=0;i<data.length;i++){
	    if(isBit1(data[i],indexOf1)){
		result[0] ^= data[i];
	    }else{
		result[1] ^= data[i];
	    }
	}
    }
	
    private int findFirstBitsIs1(int num){
	int index = 0 ;
	while((num&1)== 0){
		num>>=1;
		index++;
	}
	return index;
    }

    private boolean isBit1(int num,int index){
	num >>= index;
	return (num&1)==1;
    }
}

猜你喜欢

转载自blog.csdn.net/FireFox1997/article/details/82992231