劍指offer--查詢只出現一次的數字
阿新 • • 發佈:2018-11-13
題目:一個整形數組裡面,只有兩個數字出現了一次,其他的數字都出現了兩次,求只出現一次的數。
分析:首先考慮這個問題的一個簡單版本,一個數組裡除了一個數字外,其他的數字都出現了兩次。請寫程式找出只出現一次的數字?
這個問題的突破口在哪裡?為什麼別的數字都是出現了兩次?這裡就是為了讓我們想到異或運算的性質:任何一個數字異或它自己都等於0,若沒有這個特性,我們可以迴圈遍歷陣列,給每個出現的數記一次數,可以用hashmap的key,value實現。但是有了這個特性我們就要想到更高效的演算法。即從頭到為依次異或陣列中的每一個數字,那麼最終的結果剛好是那個只出現一次的數字,出現兩次的數字全部在異或中抵消掉了。
有了上面這個簡單的解決方案之後,回到原始問題。我們能不能把原陣列分為兩個子陣列。每個子陣列中,包含一個只出現一次的數字,而其他數字都出現了兩次,如果能這樣拆分原陣列,按前面的辦法就可以分別求出這兩個只出現一次的數字。
所以,第一步還是從頭到尾依次異或陣列中的每一個數字,那麼最終得到的結果就是兩個只出現一次的數字的異或結果。因為其他數字都出現了兩次,在異或中全部抵消掉了。第二步,由於這兩個數字肯定不一樣,那麼異或結果肯定不為0,也就是說這個結果數字的二進位制表示中至少有一位是1.,所以我們在異或結果數字中找到第一個1的位置,記為第N位。第三步,以這第N位為標準將陣列分為兩個部分。在二進位制第N位為1的都放在一個數組,為0的放到另一個數組,這樣兩個子陣列中就各包含一個只出現一次的數字,這邊大家要想一下,因為是進行異或操作,所以在第N位,兩個只出現一次的數字肯定不一樣,有了這個異或的性質才能這樣分組。
//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 temp = 0;
//依次異或陣列中的數,得到結果為兩個只出現一次的數字的異或結果 for(int i=0;i<array.length;i++) temp ^= array[i]; //獲取第一個1在異或結果中出現的位置 int indexOf1 = findFirstBitIs(temp); for(int i=0;i<array.length;i++){
//異或第一個陣列得到第一個出現一次的值
if(isBit(array[i], indexOf1))
num1[0]^=array[i];
else
num2[0]^=array[i];
}
}
//獲取第一個1在異或結果中出現的結果
public int findFirstBitIs(int num){ int indexBit = 0;
//num只要還不為0,就右移1為,計數Index+1,這樣就可以得到第一個1出現的位置
while(((num & 1)==0) && (indexBit)<8*4){
num = num >> 1;
++indexBit;
}
return indexBit;
}
//判斷第N為是否為1,作為分類標準
public boolean isBit(int num,int indexBit){
num = num >> indexBit;
return (num & 1) == 1;
}
}