第三十九题:数组中只出现一次的数字
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。
思路
hash表解:
将元素都存入hash表,我们会发现只有两个数出现1次
hash表解(代码实现):
// hash
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
if(array==null&&array.length<=1){
num1[0]=num2[0]=0;
return;
}
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0;i<array.length;i++){
if(map.containsKey(array[i])){
map.put(array[i],2);
}else{
map.put(array[i],1);
}
}
num1[0]=0;
for(Entry entry:map.entrySet()){
if((Integer)entry.getValue()==1){
if(num1[0]==0){
num1[0]=(Integer)entry.getKey();
}else{
num2[0]=(Integer)entry.getKey();
}
}
}
}
}
异或运算:
这里说明暴力解,原理跟选择排序一样
前面两种解法只是在做铺垫, 暴力解 T(N) = O(N^2) S(N) = O(1) 太耗时
hash表 T(N) = O(N) S(N) = O(N) 太耗空间
先了解一下异或运算的性质:
两个相同数字异或=0,一个数和0异或还是它本身
运算规则:
0^0=0; 0^1=1; 1^0=1; 1^1=0;
利用这个性质我们不难发现,如果数组中只有一个数出现一次,那么我们至于要进行一遍异或运算就能得到这个出现一次的数
但是数组中有两个数出现一次的数,进行一遍异或运算后,我们得到的是两个出现一次数字的异或运算结果
这个异或结果说明什么?看下面例子
array[1,1,2,2,3,3,4,5]
具体实现如下图所示:
具体实现代码如下:
// num1,num2分别为长度为1的数组。传出参数
// 将num1[0],num2[0]设置为返回结果
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
// 代码的鲁棒性
if (array == null || array.length < 2){
return;
}
// 异或的结果
int res = 0;
for (int i : array) {
res ^= i;
}
// 找不同
int index = findFirstIndex(res);
num1[0] = 0;
num2[0] = 0;
// 这里就是指的切分数组的操作,但实际上我们并不用去切分,而是直接进行异或操作就好
for (int i = 0; i < array.length;i++){
if (isBit(array[i],index)){
num1[0] ^= array[i];
}else {
num2[0] ^= array[i];
}
}
}
// 二进制数 从右往左 找到第一个 "1"
public int findFirstIndex(int n) {
int index = 0;
while ((1&n) == 0 && index < 4*8){
n = n >> 1;
index++;
}
return index;
}
// 判断这个数的二进制形式从左到右index位是否为"1"
public boolean isBit(int num, int index){
boolean flag = false;
num = num >> index;
if ((num&1) == 1){
flag = true;
}
return flag;
}
}
NowCoder(Online Coding, Please Click)