1. 程式人生 > >演算法習題61:找出陣列中兩個只出現一次的數字:一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次

演算法習題61:找出陣列中兩個只出現一次的數字:一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次

找出陣列中兩個只出現一次的數字
題目:一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。

請寫程式找出這兩個只出現一次的數字。要求時間複雜度是 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