题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
思路
法1:基于HashSet实现,利用HashSet中元素不允许重复的特性
若加入重复元素,则add方法会返回false,把这个重复元素从set中删除…
最终set中剩下的只有出现一次的两个数字
把set转换成数组,数组里的两个元素分别赋给num1[0]和num2[0](注意类型转换)
法2:利用位运算,异或运算特性:
a^a=0
0^b=b
a^b=某个数
- 数组所有元素异或后,相同的两个元素抵消,最终是两个只出现一次的元素的异或结果
- 从这个结果最右边开始找第一个1,记录下标值index
- 数组元素分组:去数组中找所有index位置上是1的元素,记为一组,剩下的就是另一组
- 只出现一次的元素一定出现在不同的组,所以只需再分别对两个分组进行异或运算,每个分组得到的就是出现一次的元素
实现
法1:HashSet
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.HashSet;
public class Solution {
//利用hashSet:不允许重复,若加入重复元素,add方法会返回false
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
HashSet<Integer> set=new HashSet<>();
//遍历数组元素,若发现set里已经存在某元素,就把已经存在的该元素删除。
//最终set中剩下的只有出现一次的那两个数
for(int i=0;i<array.length;i++){
if(!set.add(array[i])){
set.remove(array[i]);
}
}
Object[] num=set.toArray(); //set.toArray()返回一个Object类型数组
num1[0]=(int)num[0];
num2[0]=(int)num[1];
}
}
法2:位运算
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
/*数组所有元素异或后,相同的两个元素抵消,最终是两个只出现一次的元素的异或结果
从这个结果最右边开始找第一个1,记录下标值index
数组元素分组:去数组中找所有index位置上是1的元素,记为一组,剩下的就是另一组
只出现一次的元素一定出现在不同的组,所以只需再分别对两个分组进行异或运算,每个分组得到的就是出现一次的元素
*/
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
//特殊情况:数组只有两个元素
if(array.length==2){
num1[0]=array[0];
num2[0]=array[1];
}
int bitResult=0; //原数组异或运算的结果
for(int i=0;i<array.length;i++){
bitResult^=array[i];
}
//找到异或结果最右第一个1的位置
int index=FindFirst1(bitResult);
//遍历数组将数组分为两组
for(int i=0;i<array.length;i++){
//第index是1的元素进行异或,最终得到一个单次出现的数
if(isBit(array[i],index)){
num1[0]^=array[i];
}
//第index是0的元素进行异或,最终得到另一个单次出现的数
else{
num2[0]^=array[i];
}
}
}
//辅助函数:找到二进制最右开始第一个1出现的位置
public int FindFirst1(int bitResult){
int index=0; //最终得到的下标值
while(((bitResult &1)==0) && (index<8*4)){ //二进制&1,二进制最后一位是1才能得到1
bitResult=bitResult>>1; //没找到1就把二进制循环右移一位,看第二位是不是1
index++;
}
return index;
}
//辅助函数:判断某个数的二进制的右数第index位是不是1
public boolean isBit(int target,int index){
//把目标数循环右移index位,再和1作“&”运算,就能得到第index位是不是1
target=target>>index;
return (target&1)==1;
}
}
Notes:
进行位运算时,一定要考虑优先级问题,记得加括号,如(bitResult &1)==0 和 (target&1)==1