异形数问题-剑指offer40题

来源:互联网 发布:rgbcolor.js 编辑:程序博客网 时间:2024/05/12 11:58

一个整形数组中,除了两个数外,其他每个数都出现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);              }


0 0
原创粉丝点击