一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。
常规思路
我们定义一个链表,然后循环遍历数组,发现链表中有当前遍历的值,就移除;没有就添加,在保证有两个不同数字的情况下,最后链表中肯定会剩下两个数字,就是结果了。实现很简单。
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
LinkedList<Integer> list=new LinkedList<>();//链表存储当前遍历过且只出现了一次的元素
for(int i=0;i<array.length;i++)//遍历数组 添加元素
{
if(list.contains(array[i]))
{
//此处有个坑 关于LinkList的remove方法,有四个重载的方法,当参数为int类型时
//会调用移除指定位置元素的方法 因此需要强转为Object类型,移除值为i的元素
list.remove((Object)array[i]);
}
else {
list.add(array[i]);
}
}
num1[0]=list.getFirst();
num2[0]=list.getLast();
接下来是大神的思路:位运算
实现的思路:
- 首先明确一点,两个相同的数相异或结果是为0的 、
- 如果我们将所有的数都做异或运算,那么得出来的结果就是两个不同的数相与的结果
- 如何实现将两个数分离呢?很明显不好处理,但是我们有另一种方式
- 根据最后得出来的结果我们可以判断从右往左两个数的第几位是不同的
- 如果我们按照其他数字此位和两个不同数的此位是否相同 把数分为分为两组
- 那么 这两组相与的结果就是剩下的两个数
实现如下:
public void FindNumsApperaOnceWiithBit(int [] array, int num1[],int[] num2)
{
//数组格式判断
if(array==null||array.length==0||array.length%2!=0)
{
return;
}
int temp=0;//定义临时数用于保存异或数据
for(int i=0;i<array.length;i++)
{
temp=temp^array[i];
}
//如果异或结果为零 说明没有两个只出现一次的数
if(temp==0)
{
return;
}
//查找相与结果中第一位出现不同数字的位置
int index=0;//记录第一位出现不同数字的位置
while((temp&1)==0)
{
temp=temp>>1;
index++;
}
//初始化返回数组中的数据
num1[0]=0;
num2[0]=0;
//根据第index位的比特位,将数据分成两组
for(int i=0;i<array.length;i++)
{
//如果inde位比特位为1 与num[0]相与
if(inBitIsOne(array[i], index))
{
num1[0]=num1[0]^array[i];
}
else {
num2[0]=num2[0]^array[i];
}
}
}
//判断一个数的比特位上是否为1
private boolean inBitIsOne(int num,int index)
{
num=num>>index;//右移index位
if((num&1)==0)
{
return false;
}
else {
return true;
}
}