演算法習題61:找出陣列中兩個只出現一次的數字:一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次
阿新 • • 發佈:2018-12-26
找出陣列中兩個只出現一次的數字
題目:一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。
題目:一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。
請寫程式找出這兩個只出現一次的數字。要求時間複雜度是 O(n),空間複雜度是 O(1)。
------------------------------------------------------------
這題考查的是位的運算問題。
如何區分數與數的不同呢?在位運算裡不就是與 或 異或三種運算,當然可以通過異或來判斷,如果數字相等,相異或結果為0;
那麼如果我們對數組裡的所有數都進行一次異或,由於其他數字都是出現兩次,所以他們之間異或就成為0了,最後得到的結果其實就是兩個只出現一次的數字的異或值。
我們自己模擬一次:
2 3 4 4
最後就等於 10 異或 11 得到01
好了,我們現在只知道這最後是01,先考慮第一位1,在異或裡,出現1就必須是一個0與1異或,那麼這兩個數可以區分開來,可是第二位是0,這就不懂來歷了,可能是1^1 或者0^0 所以無法通過這個結果來得出兩個值。
那我們能通過什麼辦法一開始就讓兩個數區分開來異或,這樣就轉換成“在一個數組裡只有一個數字出現一次,其餘兩次,找出該數字”這就可以直接用上面著方法,因為結果就肯定是那個數了,所以我們只要想辦法分開這兩組資料,他們能分開就只能靠最後得到的那個結果,我們知道他們異或結果位出現1說明原來兩個數 在該位上是相異的,那這個不同點就找到了,只要找到第一個為1的位,用來區分陣列即可。
微軟這道題確實很巧妙。。
//============================================================================ // Name : FindEmergenceOnce.cpp // Author : YLF // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> using namespace std; void FindEmergenceOnce(int *arr, int n); int main() { int n; cin>>n; int *arr = new int[n]; int i = 0; for(i=0;i<n;i++) cin>>arr[i]; FindEmergenceOnce(arr,n); delete []arr; return 0; } void FindEmergenceOnce(int *arr, int n){ int i = 0; int ORAll=0,OR1=0,OR2=0; int key=0; for(i=0;i<n;i++){ ORAll ^= arr[i]; } //get the first 1-binary key=0; while(((ORAll>>key) & 0x1) != 1) key++; //分組 for(i=0;i<n;i++){ if(((arr[i]>>key) & 0x1) ==1) OR1 ^= arr[i]; else OR2 ^= arr[i]; } cout<<OR1<<" "<<OR2; }
8
342 432 789 432 342 567 789 981
567 981