异形数问题-剑指offer40题

这是一篇关于解决编程问题的文章,介绍了如何利用异或操作来找出一个整数数组中仅出现一次的两个数。通过将数组分为两部分并异或,然后根据异或结果的二进制位找到分组依据,最后在每个分组内再次异或,可以得到这两个唯一出现的数。文中提供了具体的Java代码实现。
摘要由CSDN通过智能技术生成

一个整形数组中,除了两个数外,其他每个数都出现2次,找出只出现了一次的那两个数?

分析:一般用异或的方法来去掉重复出现的数,两个相同的数进行异或运算后等于0,并且异或操作满足交换律和结合律。

如果一个数组中只有一个数字单独出现过一次,其他数字都分别出现过两次,那么用0异或数组中每一个元素就可以得到唯一出现过一次那个元素。


思路:把整个数组分为两部分,每个部分都包含一个只出现过一次的元素和若干对重复元素,分别求出这两个子数组中的唯一元素即可。

1. 首先用0依次异或数组中每一个元素,因为相同的元素异或得到0,所以最终的答案就等于那2个唯一的元素a^b的值。

2. 因为a,b不同,所以异或得到的答案肯定是不等于0的,那么我们就找到a^b的二进制表示中第一个为1的位,假如是第k位。而a,b两个数在第k位上是不同的,一个为0,一个为1

3. 接下来我们将第k位是1的分成一组,第k位是0的分成一组,如果2个元素相同,那么他们第k位肯定是一样的,所以肯定被分到同一组中。而a,b则被分到2组中去了。

然后我们就可以在每个分组中异或每一个元素,最终就可以得到那2个唯一的元素。

java代码如下:

/**
     * 得到num的二进制数中第一个为1的位的位置的函数
     * @param num
     * @return 二进制数中1出现的最低位的位置
     */
    public static int getFirstOnePos(int num){
    	int pos = 1;
    	//找到num的二进制数中第一个为1的位的位置
    	while((num&0x01)==0){
    		num = num>>1;
    		pos++;
    	}
    	return pos;
    }
    
    /**
     * 用来分组的函数
     * 如果地pos位为1,那么返回true。
     * @param num 要进行分组的数
     * @param pos 位置
     * @return
     */
    public static boolean divide(int num,int pos){
    	num = num>>(pos-1);
    	return (num&0x01)==1?true:false;
    }
    
    /**
     * 查找出数组中两个只出现过一次的数
     * @param a 要查找的数组
     * @param n 数组长度
     */
    public static void find(int[] a,int n){
    		int num1 = 0;
    		int num2 = 0;
          	int povit = 0;
          	//0异或数组中每一个元素,得到那两个只出现过一次的元素的异或值
          	for(int i=0;i<n;i++){
          		povit ^= a[i];
          	}
          	
          	//找到a^b的二进制表示中第一个为1的位置
          	int pos = getFirstOnePos(povit);
          	
          	for(int i=0; i<n; i++){
          		//分组
          		//第一组是pos位为1的
          		if(divide(a[i],pos)){
          			//用异或求出改组中唯一出现过一次数
          			num1 ^= a[i];
          		} else{ //第二组是pos位为0的
          			num2 ^= a[i];
          		}
          	}
          	System.out.println(num1);
          	System.out.println(num2);
          	
    }


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值