本文參考自《劍指offer》一書,代碼采用Java語言。
題目
一個整型數組里除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求時間復雜度是O(n),空間復雜度是O(1)。
思路
記住:兩個相同的數字異或等於0.
如果數組中只有一個數字只出現一次,我們從頭到尾異或每個數字,那么最終的結果剛好是那個只出現一次的數字。
而本題里數組中有兩個數字只出現一次,如果能夠將數組分為兩部分,兩部分中都只有一個數字只出現一次,那么就可以解決該問題了。
求解方法:
我們依舊從頭到尾異或每個數字,那么最終的結果就是這兩個只出現一次的數字的異或結果,由於兩個數不同,因此這個結果數字中一定有一位為1,把結果中第一個1的位置記為第n位。因為是兩個只出現一次的數字的異或結果,所以這兩個數字在第n位上的數字一定是1和0。
接下來我們根據數組中每個數字的第n位上的數字是否為1來進行分組,恰好能將數組分為兩個都只有一個數字只出現一次的數組,對兩個數組從頭到尾異或,就可以得到這兩個數了。
測試算例
1.功能測試(數組中有多對重復的數字;無重復的數字)
Java代碼
//題目:一個整型數組里除了兩個數字之外,其他的數字都出現了兩次。請寫程序 //找出這兩個只出現一次的數字。要求時間復雜度是O(n),空間復雜度是O(1)。 public class NumbersAppearOnce { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { if(array==null || array.length<2) return; int resultExclusiveOR=0; for(int i=0;i<array.length;i++) resultExclusiveOR^=array[i]; int indexOf1=0; while(((resultExclusiveOR&1)==0) && (indexOf1<=4*8)){ resultExclusiveOR=resultExclusiveOR>>1; //只有n>>1不完整,要n=n>>1 indexOf1++; } num1[0]=0; num2[0]=0; for(int i=0;i<array.length;i++){ if(((array[i]>>indexOf1)&1)==1) num1[0]^=array[i]; else num2[0]^=array[i]; } } }
收獲
1.當一個數字出現兩次(或者偶數次)時,用異或^ 可以進行消除。一定要牢記 異或的這個功能!
2.將一組數字分為兩組,可以根據某位上是否為1來進行分組,即根據和1相與(&1)的結果來進行分組。
3.判斷某個數x的第n位(如第3位)上是否為1,
1)通過 x&00000100 的結果是否為0 來判斷。(不能根據是否等於1來判斷)
2)通過(x>>3)&1 是否為0 來判斷
4.將某個數x右移m位,一定要寫成 x=x>>m;而不能只寫成 x>>m;這個語句