剑指Offer——数组中只出现一次的数字(一个很帅的异或解法)

题目:算法

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

 

看题目脑子里就出现作法了:spa

遍历,用个HashMap来记录出现的次数,而后再遍历HashMap返回的EntrySet找出出现一次的数字搞定。code

 代码顺便上下吧:blog

public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        Integer count;
        for(int temp : array) {
            if( (count = map.get(temp)) == null )map.put(temp, 1);
            else map.put(temp, ++count);
        }
        num1[0] = -1;num2[0] = -1;
        Set<Entry<Integer, Integer>> entrySet = map.entrySet();
        for(Entry<Integer, Integer> temp : entrySet) {
            if( (count = temp.getValue()) == 1 && num1[0] == -1)num1[0] = temp.getKey();
            else if(count == 1)num2[0] = temp.getKey();
        }
    }

 

 

而后看牛客网的讨论,原来能够用异或操做很帅气地解决这个问题哈哈,来记录一下。get

 

基础知识:it

1. 0和任何数字异或都为它本身,这个也很容易理解,拿个数字试试就知道辽。
2. 结合律:a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c;
3. a ⊕ b ⊕ a = b.
固然还有其余运算规律,能够去百度百科看哈哈:

 

 

思路:(来自牛客的一个小伙子)io

连接: https://www.nowcoder.com/questionTerminal/e02fdb54d7524710a7d664d082bb7811
来源:牛客网
只有一个数出现一次时,咱们把数组中全部的数,依次异或运算,最后剩下的就是落单的数,由于成对儿出现的都抵消了。
 
依照这个思路,咱们来看 两个数(咱们假设是AB)出现一次的数组。咱们首先仍是先异或,剩下的数字确定是 A、B异或的结果这个结果的二进制中的1,表现的是A和B的不一样的位
 
咱们就取第一个1所在的位数,假设是第3位,接着把原数组分红 两组,分组标准是第3位是否为1。如此, 相同的数确定在一个组,由于相同数字全部位都相同,而不一样的数, 确定不在一组。而后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。

 

 

而后上一下我本身根据这个思路写的代码,已经经过:class

/*高端的位运算法*/
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int firstXorResult = 0;//0和任何数异或都为自己
        for(int temp : array) {
            firstXorResult ^= temp;//异或知足结合率,a^b^a = b
        }
        //这样获得的firstXorResult就是惟一两个只出现一次的数字的亦或结果,也就是这个firstXorResult中为1的地方,就是这两个数字在位上面不一样的地方
        int shiftBit = 0;
        while(shiftBit <= 31) {//这个循环是看从最低位开始,哪一个位是第一个不一样的,也就是为1的
            if(  (firstXorResult & (1 << shiftBit)) != 0 )break;
            shiftBit++;
        }
        List<Integer> list1 = new ArrayList<Integer>();
        List<Integer> list2 = new ArrayList<Integer>();
        
        for(int temp : array) {
            //根据刚刚的shiftBit,把数字分红两份,一份相与为0,一份不为0。首先确定那两个只出现一次的数字确定分开的;而后相同的数字确定分到一个list
            if(  (temp & (1 << shiftBit)) == 0  ) {
                list1.add(temp);
            } else {
                list2.add(temp);
            }
        }
        
        int result1 = 0, result2 = 0;
        for(int temp : list1) {//异或结束获得的就是结果
            result1 ^= temp;
        }
        for(int temp : list2) {
            result2 ^= temp;
        }
        num1[0] = result1;
        num2[0] = result2;
    }
相关文章
相关标签/搜索