劍指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;
    }
相關文章
相關標籤/搜索