程序员面试题精选100题<1>-数组中只出现一次的数字

题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

分析:   该分析过程转载至 (http://zhedahht.blog.163.com/blog/static/2541117420071128950682/)

首先我们考虑这个问题的一个简单版本:一个数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。

      这个题目的突破口在哪里?题目为什么要强调有一个数字出现一次,其他的出现两次?我们想到了异或运算的性质:任何一个数字异或它自己都等于0。也就是说,如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现依次的数字,因为那些出现两次的数字全部在异或中抵消掉了。

有了上面简单问题的解决方案之后,我们回到原始的问题。如果能够把原数组分为两个子数组。在每个子数组中,包含一个只出现一次的数字,而其他数字都出现两次。如果能够这样拆分原数组,按照前面的办法就是分别求出这两个只出现一次的数字了。

我们还是从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。因为其他数字都出现了两次,在异或中全部抵消掉了。由于这两个数字肯定不一样,那么这个异或结果肯定不为0,也就是说在这个结果数字的二进制表示中至少就有一位为1。我们在结果数字中找到第一个为1的位的位置,记为第N位。现在我们以第N位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0。

现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现了两次。因此到此为止,所有的问题我们都已经解决。

代码:

  1: #include <iostream>

  2: using namespace std ;

  3: // find the first set bit int the num

  4: // get this algo from linux kernel

  5: int findFirstSetBit(int num)

  6: {

  7:     int pos = 1 ;

  8:     if (!num){

  9:         return 0 ;

 10:     }

 11:     if (!(num & 0x0ffff)){

 12:         num >>= 16 ;

 13:         pos += 16 ;

 14:     }

 15:     if (!(num & 0x0ff)){

 16:         num >>= 8 ;

 17:         pos += 8 ;

 18:     }

 19:     if (!(num & 0x0f)){

 20:         num >>= 4 ;

 21:         pos += 4 ;

 22:     }

 23:     if (!(num & 0x3)){

 24:         num >>= 2 ;

 25:         pos += 2 ;

 26:     }

 27:     if (!(num & 0x1)){

 28:         num >>= 1 ;

 29:         pos += 1 ;

 30:     }

 31:     return pos ;

 32: }
  1: void findTwoNum(int* array,int len ,int& a, int&b)

  2: {

  3:     int ret = 0 ;

  4:     int pos = 0 ;

  5:     int tmp = 0 ;

  6:     a = b = 0 ;

  7:     for (int i=0 ;i<len ; ++i){

  8:         ret ^= array[i] ;

  9:     }               

 10:     // the ret must be non zero   

 11:     pos = findFirstSetBit(ret) ;

 12:     if (!pos){     

 13:         return ;

 14:     }

 15:     //compute tmp whose value is 2^(pos-1)

 16:     tmp = 1 << (pos-1) ;

 17:     for (int i=0 ;i<len ; ++i){

 18:         if (array[i] & tmp){

 19:             a ^= array[i] ; 

 20:         }else{

 21:             b ^= array[i]  ;

 22:         }

 23:     }

 24: }

 

  1: // unit test

  2: int main()

  3: {

  4:     int array[20]= {1,2,3,4,5,6,7,8,9,50, \

  5:         1,2,3,4,5,6,7,8,9,60}  ;

  6:     int a ; 

  7:     int b ;

  8:     a = b = 0 ;

  9:     findTwoNum(array, 20, a, b) ;

 10:     if ( !a && !b){

 11:         cout << "Some Error Happend !" << endl ;

 12:     }else{

 13:         cout << "The two num is "<< a << " " << b << endl ;

 14:     }

 15: }
posted @ 2012-03-15 15:13  Better-zyy  阅读(250)  评论(0编辑  收藏  举报