问题描述:
一个整形数组里除了一个数字以外,其他数字都出现了两次 。 找出这个只出现一次的数字。
要求:时间复杂度为O(n), 空间复杂度是O(1)
分析:
使用异或运算:任何一个数字异或他自己都等于0,如果从头到尾一次异或数组中的每一个数字,那些出现两次的数字全部在异或中会被抵消掉,最终的结果刚好是这个只出现一次的数字
代码:
private int findNotDouble(int[] a) {
if(a == null){
return Integer.MIN_VALUE;
}
int result = a[0];
int len = a.length;
for(int i=1; i<len; i++){
result ^= a[i];
}
return result;
}
测试代码:
@Test
public void main(){
int a[] = { 1,2,3,2,4,3,5,4,1 };
System.out.println(findNotDouble(a));
}
结果:
引申:如果题目改为数组a中,一个整形数组除了一个数字之外,其他数字都出现了3次,那么如何找出这个数
如果数组中的所有数都出现n次,那么这个数组中的所有数对应的二进制数中,各个位上的1出现的个数均可以被n整除。
以n=3为例,有数组{ 1,1,1,2,2,2 } ,他么对应的二进制表示为 01, 01 , 01 , 10, 10, 10.显然,这个数组中所有数字对应的二进制数中第0位有3个1,第1位有3个1.
对于本题而言,假设出现一次的这个数为a , 那么去掉a后其他所有数字对应的二进制数中的每个位置出现1的个数为3的倍数。
因此可以对数组中所有数字对应的二进制数中的各个位置上1的个数对3取余,就可以得到出现1次的这个数的二进制表示,从而可以找出这个数。
代码:
/**
* 如果数组中的所有数都出现n次,那么这个数组中的所有数对应的二进制数中。各个位上的1的个数均可以被n整除
* @param a
* @param times
* @return
*/
public int findOnce(int a[], int times){
if( a == null){
return Integer.MAX_VALUE;
}
int result = 0;
int n = a.length;
int[] bitCount =new int[32];
// 计算数组中所有元素对应的二进制数各个位置上出现1的次数
for(int i=0; i<n; i++){
for(int j=0; j<32; j++){
bitCount[j] += ( (a[i] >> j) & 1);
}
}//
// 若某位上的结果不能被整除,则肯定目标数字在这一位上
for(int i=0; i<32; i++){
if(bitCount[i] % times != 0){
result += (1 << i);
}
}
return result;
}