題目:一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)。
思路:題目要求時間複雜度是O(n),空間複雜度是O(1),這說明基於比較的辦法求解無法完成,這題需要異或的性質,異或(同為0,異為1,相當於不進位加法)
因為其它數都出現兩次,當掃描完一次之後,將所有的數做異或,那些相同的數都會變成0,結果是兩個不同的數的異或。例如,9,4,4,2做異或,4,4異或為0,結果就相當於9異或2。
這裡有兩個數字不同,假設只有一個數字不同,那麼,我們只需要掃描一遍,所有數做異或就可以得出結果。有兩個數字怎麼辦呢?思路就是將這兩個數劃分到兩個不同的組去。
劃分依據是什麼呢?
1,可以這麼做,先將所有的數異或起來,假設結果為11001100,那麼可以用最低的1位劃分(即第2位,低到高,從0數起)[實質上可以用任何一個1劃分,只是這是最方便的],為什麼1可以劃分開兩個不同的數呢?將兩個數寫成二進位的形式,那麼異或結果顯示出的1位(同時兩個不同的數相異或必然有1,因為同則必為0),都是二者相應位不同的。(異為1,同為0),因此用1劃分則不同的兩數必然被分到兩個不同組
2,第二步,將兩個子數組的數做異或就能得出結果,因為相同的數會得0.
3,小技巧,中途需要判斷位是否為1,方法是:先將要判斷的位通過右移移到最末位,然後與0000.....00001做位與,末位是1,則結果是1,若末位是0,結果是0
代碼:
/*一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)*/#include<iostream>using namespace std;int FindFirstbitis1(int sum)//找到第一個位是1(右往左)的索引號{int index=0;while((1 & sum)==0)//和000..00001做與,若末位為0,即等於0,若末位為1,即為1{sum=sum>>1;++index;}return index;}int judgeindexbitis1(int num,int index){num = num >> index;//右移index位,使要判斷的一位處於最末位return(1 & num);//和000..0001與,1則返回1,0則返回0}void xor(int* A,int len){int sum=0;//兩相異的數for(int i=0;i<len;++i){sum =sum ^ A[i];}int index=FindFirstbitis1(sum);int num1=0,num2=0;//儲存結果for(int i=0;i<len;++i){if(judgeindexbitis1(A[i],index))num1 =num1 ^ A[i];else num2=num2 ^ A[i];}cout<<num1<<" "<<num2<<endl;}void main(){int A[]={9,0,0,3,3,8,8,55,55,8888,8888,5};int len=sizeof(A)/sizeof(A[0]);xor(A,len);}