来源于《剑指offer》,书上用C/C++写的
一个整数数组中有一个数字只出现1次,而其它所有数字都是出现2次,找出该数?
解答:将该数组的所有数异或得到的即是该数,因为a⊕b⊕a=b
如果数组中出现2个这样的数字,该如何?
解答:依然先将所有数据异或,得到的是这2个只出现一次的数字异或的结果,这2个数不相等,则得到的结果一定不为0,即它的二进制至少有1个1,而这个1一定只来自这2个数其中一个。那么先找到一个某位这个位置也为1的数,且只有该位为1。那么数组中的数据就可以分为2组了,一组为该位二进制为1的,另一组为该位二进制不为1的,那2个只出现一次的数字一定分在不同的组中,出现2次的数据一定分在同一组中。那么接下来第一步,是识别数字的分组,分在同一组的数组全部异或即可以得到该分组中只出现一次的数字。
package algorithm;
public class SearchTheOnceNumbers {
public static void main(String[] args)
{
int test1[] ={2,3,5,5,3};
System.out.println(findTheOnceNumber(test1));
int test2[] ={2,3,6,8,8,3};
findTheOnceNumbers(test2);
}
//数组中只存在一个只出现1次的数字,其它数字都是出现2次
public static int findTheOnceNumber(int[] number)
{
if(number.length<=0) return 0;
int result = 0;
for(int i=0; i<number.length; i++)
{
result ^=number[i];
}
return result;
}
//数组中有2个只出现1次的数字,其它数字都是出现2次
public static void findTheOnceNumbers(int[] number)
{
if(number.length<=0) return;
int num0 =findTheOnceNumber(number);
int firstNum1 = findTheFirstOneInNumber(num0);
System.out.println(firstNum1);
int result1=0,result2=0;
for(int i=0;i<number.length;i++)
{
//该特定位为1的数字全部异或得到的一定是该位为1的那个只出现1次的数,
//其它所有数异或得到的一定是该位不为1的那个只出现1次的数
if(firstNum1==(firstNum1&number[i])) result1 ^=number[i];
else result2 ^=number[i];
}
System.out.println(result1);
System.out.println(result2);
}
//找出最低位为1的数字,这个1一定来自那两个只出现1次的数字的其中一个
public static int findTheFirstOneInNumber(int number)
{
if(number ==0) return 0;
int result =1;
while(!(result==(result&number))) result = result<<1;
return result;
}
}