題目
一個整型數組里除了1個數字之外,其他的數字都出現了兩次,請寫程序找出這個只出現一次的數字。要求時間復雜度是 O(n),空間復雜度是 O(1),例如輸入數組{2, 4, 3, 3, 2, 5 },因為只有 4 這個數字只出現一次,其他數字都出現了兩次,所以輸出 4
分析
本題以及延伸題目,在劍指offer上有詳細描述。利用異或的特性,x^y^x=y^x^x=y。對數組所有元素一次進行異或操作,最終得到的值就是那個只出現一次的數字
代碼
1 int FindOnceNum(int arr[],int len) 2 { 3 if (arr==NULL||len<=0) 4 { 5 throw std::exception("Invalid input."); 6 } 7
8 int ret=0; 9 for(int i=0;i<len;i++) 10 { 11 ret=ret^arr[i]; 12 } 13
14 return ret; 15 }
那么,當數組中有2個只出現1次的數字呢?例如輸入數組{2, 4, 3, 3, 6, 2, 5 },因為4和6 這兩個數字都只出現一次,其他數字都出現了兩次,應輸出 4,6
思路分析
假設兩個只出現一次的數字分別為a、b,對數組元素進行兩兩異或后得到的值為c,可知c=a^b。因為a和b一定不同,所以c不等於0,那么c的二進制表示中一定有一位是1,即a,b在此位上分別為0,1或1,0。假設該位置是從低位起第x位,那么將數組分成兩組,一組中的數字在第x位是0,另一組中的數字在第x位是1,則a和b分別屬於兩個子數組。分別求子數組中唯一只出現1次的數字,即可得到a和b
代碼
1 bool is_true_bit(int num,int index) 2 { 3 return (num>>index)&0x01; 4 } 5
6 void FindOnceNums(int arr[],int len) 7 { 8 int xor_num=0; 9 for(int i=0;i<len;i++) 10 { 11 xor_num=xor_num^arr[i]; 12 } 13
14 int index=0; 15 while (index<32) 16 { 17 if (is_true_bit(xor_num,index)) 18 { 19 break; 20 } 21 index++; 22 } 23
24 int a=0,b=0; 25 for(int i=0;i<len;i++) 26 { 27 if (is_true_bit(arr[i],index)) 28 { 29 a=a^arr[i]; 30 }else
31 { 32 b=b^arr[i]; 33 } 34 } 35
36 cout<<a<<endl; 37 cout<<b<<endl; 38
39 }
延伸1:
如果要求數組中唯一只出現1次的3個數字呢?
思路是一樣的,3個數字的二進制表示中必有1位,一個數字a在此位上是1,其他兩個數字b、c在此位上是0。先以此將數組分為兩組,求出a,再求子數組中唯一出現1次的兩個數字b和c。
延伸2:找出數組中唯一出現兩次的數
假設你有一個用1001個整數組成的數組,這些整數是任意排列的,但是你知道所有的整數都在1到1000(包括1000)之間。此外,除一個數字出現兩次外,其他所有數字只出現一次
分析
從題目中可以知道,這1001個整數是1到1000的連續整數(任意排列)加上一個多出1次的任意數字(在1到1000之間)。那么xor_num=1^2^3^···X···N-1^N,xor_num2=1^2^3^···X^X···N-1^N,將xor_num和xor_num2異或即可得到X
延伸3:找出數組中唯一出現兩次的數(任意整數數組)
一個數組,除了有1個數字出現2次外,其余數字均出現1次,求出現2次的那個數字
本題只好用hash的內存方式記錄次數了,暫時沒想到好的方法