题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字
num1,num2分别为长度为1的数组。传出参数
将num1[0],num2[0]设置为返回结果
方法一、遍历所有元素,将出现一次的元素保存到集合里。
首先查看集合中是否包含当前元素,如果包含说明这个元素出现了两次,则把它删除,如果不包含则将这个元素添加到集合中。
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
ArrayList<Integer> list = new ArrayList<>();
for(int i=0;i<array.length;i++){
if(list.contains(array[i])){
for (int i1=0;i1<list.size();i1++){
if(list.get(i1)==array[i]){
list.remove(i1);
}
}
}
else
list.add(array[i]);
}
num1[0] = list.get(0);
num2[0] = list.get(1);
}
方法二、运用异或运算。
思路:
(1)题中给出了一个数组除了两个数字之外,其他的数字都出现了两次。则可以联想到两个相同的数的异或的结果为0,而任何数异或0则还是这个数。
(2)依照这个思路,我们可以将所有数依次进行异或,最后得到的数一定是两个出现一次的数的异或后的结果,将他记录为result。
(3)接下来就是通过这个异或后的结果找到两个数。根据异或运算的特点可知,result的二进制形式为1的位,就是两个出现一次的数中不同的位.
以下举个例子理解这句话
51^42 结果为011001=25。这样为了区分51和42就可以找到011001的第一个1所在的位,即第一位,51为1,42为0。
(4)知道了区分条件,那么就可以将原数组分为两组。相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。分组标准是由第三步确定。如此,然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。
具体代码如下
public void FindNumsAppearOnce(int[] array, int[] num1, int[] num2) {
int length = array.length;
if(length == 2){ //只有两个元素的时候
num1[0] = array[0];
num2[0] = array[1];
return;
}
int Result = 0;
for(int i = 0; i < length; ++i){
Result ^= array[i];
} //Result得到的结果为1的位是两个只出现一次的数的不同位
int index = findFirst1(Result); //找到第一个1,也就是第一个不同的位
for(int i = 0; i < length; ++i){
if(isBit1(array[i], index)){ //确定当前为哪一组
num1[0] ^= array[i];
}else{
num2[0] ^= array[i];
}
}
}
private int findFirst1(int bitResult){
int index = 0;
while(((bitResult & 1) == 0) && index < 32){
bitResult >>= 1;
index++;
}
return index;
}
private boolean isBit1(int target, int index){
return ((target >> index) & 1) == 1;
}