算法系列——數組中只出現一次的數字

題目描述

一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。

舉例說明
例如輸入數組{2, 4, 3, 6, 3, 2, 5 },因爲只有 4 、6 這兩個數字只出現一次,其他數字都出現了兩次,所以輸出 4 和 6 。

解題思路

這兩個題目都在強調一個(或兩個)數字只出現一次,其他的出現兩次。這有什麼意義呢?我們想到異或運算的一個性質:任何一個數字異或它自己都等於 0。也就是說, 如果我們從頭到尾依次異或數組中的每一個數字,那麼最終的結果剛好是那個只出現一次的數字,因爲那些成對出現兩次的數字全部在異或中抵消了。

想明白怎麼解決這個簡單問題之後,我們再回到原始的問題,看看能不能運用相同的思路。我們試着把原數組分成兩個子數組,使得每個子數組包含一個只出現一次的數字,而其他數字都成對出現兩次。如果能夠這樣拆分成兩個數組, 我們就可以按照前面的辦法分別找出兩個只出現一次的數字了。

我們還是從頭到尾依次異或數組中的每一個數字,那麼最終得到的結果就是兩個只出現一次的數字的異或結果。因爲其他數字都出現了兩次,在異或中全部抵消了。由於這兩個數字肯定不一樣,那麼異或的結果肯定不爲 0,也就是說在這個結果數字的二進制表示中至少就有一位爲 1 。我們在結果數字中找到第一個爲 1 的位的位置,記爲第 n 位。現在我們以第 n 位是不是 1 爲標準把原數組中的數字分成兩個子數組,第一個子數組中每個數字的第 n 位都是 1,而第二個子數組中每個數字的第 n 位都是 0。由於我們分組的標準是數字中的某一位是 1 還是 0 , 那麼出現了兩次的數字肯定被分配到同一個子數組。因爲兩個相同的數字的任意一位都是相同的,我們不可能把兩個相同的數字分配到兩個子數組中去,於是我們已經把原數組分成了兩個子數組,每個子數組都包含一個只出現一次的數字,而其他數字都出現了兩次。我們已經知道如何在數組中找出唯一一個只出現一次數字, 因此到此爲止所有的問題都已經解決了。

程序實現

//num1,num2分別爲長度爲1的數組。傳出參數
//將num1[0],num2[0]設置爲返回結果
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {

        if (array == null || array.length < 2) {
            return ;
        }
        int xor = 0;
        for (int i : array) {
            xor ^= i;
        }
        int indexOf1 = findFirstBit1(xor);
        for (int i : array) {
            if (isBit1(i, indexOf1)) {
                num1[0]^= i;
            } else {
                num2[0]^= i;
            }
        }

    }
    private  int findFirstBit1(int num) {
        int index = 0;
        while ((num & 1) == 0 && index < 32) {
            num >>>= 1;
            index++;
        }
        return index;
    }
    private  boolean isBit1(int num, int indexBit) {
        num >>>= indexBit;
        return (num & 1) == 1;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章