剑指offer:数组中只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。

常规思路
我们定义一个链表,然后循环遍历数组,发现链表中有当前遍历的值,就移除;没有就添加,在保证有两个不同数字的情况下,最后链表中肯定会剩下两个数字,就是结果了。实现很简单。

    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;
		}
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值