1. 程式人生 > >【C++】找陣列中唯一出現兩次的數

【C++】找陣列中唯一出現兩次的數

假設你有一個用1001個整陣列成的陣列,這些整數是任意排列的,但是你知道所有的整數都在1到1000(包括1000)之間。此外,除一個數字出現兩次外,其他所有數字只出現一次。假設你只能對這個陣列做一次處理,用一種演算法找出重複的那個數字。如果你在運算中使用了輔助的儲存方式,那麼你能找到不用這種方式的演算法嗎?

方法一使用輔助的儲存方式,該選擇何種儲存方式呢?可使用hash的儲存方式,以1到1000作為hash表的索引,遍歷原陣列,統計各數字出現的個數並存儲到以該數字為索引值的hash表中,若某個hash[x]的值為2則退出迴圈,x就是重複出現兩次的數字。時間複雜度最壞是O(n)。優點:高效率,缺點:消耗的記憶體空間過大。

程式碼如下所示:

 int hash[7]={0};  
    for(int i=0;i<7;++i){  
        if(++hash[a[i]]==2){  
            cout<<"result:"<<a[i];  
            break;  
        }  
    }  

這個方法是本人認為解這裡問題的比較好的一種方法,對於問題的變形也具有一定的魯棒性。比如題目改變成:在一個數組中有1000個數字,數字範圍是1到1000,其中只有一個是重複的剩下的都不重複。

方法二,採用異或的方式來求取

思想:1001個數異或結果與1-1000異或的結果再做異或,得出的值即位所求。


原理:
設重複數為A,其餘999個數異或結果為B。1001個數異或結果為A^A^B。1-1000異或結果為A^B。由於異或滿足交換律和結合律,
則有 (A^B)^(A^A^B)=A^B^B=A

程式碼如下:

 int a[7]={1,4,5,6,2,3,5};
    int i=0,j=0;
    int b[6]={1,4,6,2,3,5};
    int temp=a[0];
    for(i=1;i<7;++i){
        temp=temp^a[i];
    }
    int temp2=b[0];
    for(j=1;j<6;++j){
        temp2=temp2^a[j];
    }
    int result = temp^temp2;
    cout<<"result:"<<result;

用異或的方法解決此類問題可擴充套件性也非常好,比如,當題目變形為:在一個數組中只有一個數是不重複的剩餘的數都出現了兩次,現在求不重複的那個數。

思路:異或中兩個相同的數相異或結果為0,0與其他數異或都是其他數。程式碼如下:

 int a[5]={5,4,5,1,4};  
    int i=0,j=0;  
    int temp=a[0];  
    for(i=1;i<5;++i){  
        temp=temp^a[i];  
    }  
    cout<<"result:"<<temp;

方法三,求和法

這個是完全的數學思想的一種方法:想將原陣列S1的所有元素的加起來,然後再將S2={1,2,...,1000}折1000個數的所有元素加起來,最後做減法就能得到出現僅兩次的那個數了。

但是這個方法的侷限性很強,比如將題目變形一下:在一個數組中有1000個數字,數字範圍是1到1000,其中只有一個是重複的剩下的都不重複(也就是在這1000個數據中有一個數出現了兩次,有一個數一次都沒出現),若是求那個重複的數字是多少?此時用這個方法就行不通了。此時使用方法一能夠解決。

若是求那個沒出現的數字是多少,就需要方法一和方法三合作求出了。先用方法一求出重複的數字x,然後sum(s2)-(sum(s1)-x);其中s1是輸入的陣列,s2是1到1000的陣列。

這個題目只是這類題目中的一個,變形的有很多。