剑指offer--一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

尝试说明大家普遍使用的一种方法:利用位运算来实现。

三步走:

1.首先将数组元素依次异或,得到值resultExclusiveOR,接下来要利用这个数字将原数组分为两部分。

2.利用子函数FindFirstBitIs1()来找FindFirstBitIs1中第一次出现1的位,假设为b位。

3.接下来就是利用函数IsBit()来实现区分b位为1的一组,不为1的是另一组。

class Solution {
public :
     void FindNumsAppearOnce(vector< int > data, int * num1, int * num2) {
         if (data.size() < 2)
             return ;
          
         int resultExclusiveOR = 0;
         for ( int i = 0; i < data.size(); i++){
             resultExclusiveOR ^= data[i];
         }
          
         unsigned  int indexOf1 = FindFirstBitIs1(resultExclusiveOR);
          
         *num1 = *num2 = 0;
         for ( int j = 0; j < data.size(); j++){
             if (IsBit1(data[j], indexOf1))
                 *num1 ^= data[j];
             else
                 *num2 ^= data[j];
         }
  
     }
      
     unsigned  int FindFirstBitIs1( int num){
         int indexBit = 0;
         while (((num & 1) == 0) && (indexBit < 8* sizeof ( int ))){
             num = num >> 1;
             indexBit++;
         }
          
         return indexBit;
     }
      
     bool IsBit1( int num, unsigned  int indexBit){
         num = num >> indexBit;
         return (num&1);
     }
      
};

怎么实现的呢,刚开始我也是一头雾水,但是仔细看一会发现,例如,2,3,4,4,5,5,二进制代码依次为10,11,100,100,101,101。将他们依次异或(^)后,结果为01,显然相同的4和4,5和5根本不影响不相同的数2和3之前的异或,这是一点,假如2,4,4,5,5.异或之后结果10,即2;3,4,4,5,5。异或之后结果为11,即3,;好了这一个异或解决了两个问题,找到单独存在的数和如何提出来单独的数,只要把单独存在且不同的两个数分到两个数组里然后异或,结果就是我们要的,怎么分数组,整体数组异或结果位出现1可以说明原来两个不同的数在这一位是不同的,那这个突破点就找到了,只要从右到左找到第一个1所在位,然后按照在这一位是1为标准划分为两个数组就可以了。举个例子更形象,7和10,二进制依次为0111和1010,异或结果为1101,只要把二进制第一位是1的分到A数组,不是1的分到B数组,就自然把7和10分到两个数组了。


猜你喜欢

转载自blog.csdn.net/qq_34885598/article/details/80719017