找出数组中两个只出现一次的数字;异或运算^的一个作用

来源:互联网 发布:淘宝店铺装修 骗局 编辑:程序博客网 时间:2024/04/30 09:29

【题 目】一个整型数组中除了两个数字外,其他的数字都出现两次。请找出这两个只在数组中出现一次的数字。要求时间复杂度O(n),空间复杂度O(1)。

 

【思 路】首先我们考虑一个稍微简单点的情况:如果这个数组中只有一个数字出现且仅出现一次,其他数字都出现两次,我们应该怎么样找出这个数字呢?我们题目说数字出现两次有什么深意呢?我们很容易联想到异或运算,因为任何一个数字和自身异或的结果为0;知道了这点,我们就很容易知道,我们将所有的数字进行异或,其结果就是仅出现一次的数字,因为其他所有的数字都两两异或为0了。

  有了上面那个简单题目作为引子,我们很容易想到,如果我们将原题目的数组成功的分为两个子数组,而每个子数组恰好含有一个仅出现一次的数字,那么我们就可以根据上面的思路直接求解。怎么划分这两个子数组呢?

  我们仍然将原数组中的所有数字进行异或运算,容易知道,异或的结果实际上就是两个仅出现一次的数字的异或结果,因为这两个数字不相等,所以异或的结果肯定不为0,我们可以找到异或结果中,第一个为1的位,这说明在该位上,必然有一个数字为1,另一个数字在该为上为0;我们可以按照这个结果,对所有该位上为1的数字分为一组,而将该位上为0的位分为另一组,这样我们就成功的讲原问题转换为两个简单的子问题。再对子问题全部异或,即可获得两个仅出现一次的数字。按照这个思路,我们可以得到如下的代码:

复制代码
 1 #include<iostream> 2 #include<string> 3 using namespace std; 4  5 //判断一个数number的第bitIndex位是否为1 6 bool IsBit1(int number,unsigned int bitIndex) 7 { 8     number = number>>bitIndex; 9     return (number & 1);10 }11 12 //找到num中第一个位是1的位13 unsigned int FindFirstbitOf1(int num)14 {15     int bitIndex = 0;16     while(bitIndex < 32 && ((num & 1) == 0))17     {18         num = num>>1;19         bitIndex++;20     }21 22     //该函数的另一种循环结构,完全等价23 /*    for(bitIndex = 0;bitIndex < 32;++bitIndex,num = num>>1)24     {25         if((num & 1) ==1)26             break;27     }28 */29     return bitIndex;30 }31 32 void FindNumbersAppearOnce(int data[],unsigned int length,int &num1,int &num2)33 {34     //无效输入35     if(data == NULL || length < 2)36         return;37 38     //得到num1异或num239     int resultOfBitOR = 0;40     for(int i = 0;i < length;++i)41     {42         resultOfBitOR ^= data[i];43     }44 45     //找到num1^num2的结果中第一个为1的位46     unsigned int index = FindFirstbitOf1(resultOfBitOR);47 48     num1 = 0;49     num2 = 0;50 51     //将index位的取值是否为1分为两组52 //将每一组的全部数字做异或53     for(int j= 0;j < length;++j)54     {55         if(IsBit1(data[j],index))56             num1 ^= data[j];57         else58             num2 ^= data[j];59     }60 61 62 }63 64 int main()65 {66     cout<<"Please Enter your ArrayLength:"<<endl;67     int arraylength = 0;68     cin>>arraylength;69 70     int *array = new int[arraylength];71     cout<<"Please Enter the numbers in your Array:"<<endl;72     for(int k = 0;k < arraylength;++k)73     {74         cin>>array[k];75     }76 77     int result1 = 0;78     int result2 = 0;79     FindNumbersAppearOnce(array,arraylength,result1,result2);80 81     cout<<"the numbers appear once in your array are:"<<endl;82     cout<<result1<<"\t"<<result2<<endl;83 84     return 0;85 }
复制代码

  测试及运行结果如下:


 

References:

何海涛博客:http://zhedahht.blog.163.com/blog/static/2541117420071128950682/

注:

1)本博客所有的代码环境编译均为win7+VC6。所有代码均经过博主上机调试。

2)博主python27对本博客文章享有版权,网络转载请注明出处http://www.cnblogs.com/python27/。对解题思路有任何建议,欢迎在评论中告知。

 

 

交换两个整数的值而不必用第三个参数
a = 9;
b = 11;

a=a^b; 1001^1011=0010
b=b^a; 1011^0010=1001
a=a^b;  0010^1001=1011

a = 11;
b = 9;

原创粉丝点击