一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。
集合法
其实,我觉得使用HashSet挺好的,时间复杂度也可以接受。
遍历数组
- 如果数不在集合中,添加到集合中
- 如果数在集合中,从集合中去掉
遍历完成之后,数组中只剩下了两个数,也就是要求的单身数。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.*;
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
Set<Integer> set = new HashSet<>();
for(Integer i : array){
// HashSet 时间复杂度为O(1)
if(set.contains(i)) set.remove(i);
else set.add(i);
}
ArrayList<Integer> list = new ArrayList<>(set);
num1[0] = list.get(0);
num2[0] = list.get(1);
}
}
位运算
这个需要对Java位运算有一定的熟悉。
异或: 1000 XOR 1101 = 0101
相同为0,不同为1
与:1000 & 1100 = 1000
同时为1 的时候为1,否则为0
对于这一题:
- 把所有的数字亦或一下,相同的数字亦或后全部变成了0,相当于只把两个不同的数异或了。
- 两个不同数字亦或结果肯定不为0,找到结果中不为0的位。
- 对于整个数组,根据该位是否为0分为两组。每组异或即可得到结果。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
int sum = 0;
for(int i : array) sum ^= i; // 所有数字异或
int flag = 1; // 此时flag最低位为1
while((sum & flag) == 0) flag <<=1; // 寻找标志位
for(int i : array){
if((i & flag) == 0) num1[0] ^= i; // 标志位为0组
else num2[0] ^= i;// 标志位为1组
}
}
}