【C++】找数组中唯一出现两次的数

来源:互联网 发布:爱奇艺网络剧 编辑:程序博客网 时间:2024/05/22 19:36

假设你有一个用1001个整数组成的数组,这些整数是任意排列的,但是你知道所有的整数都在1到1000(包括1000)之间。此外,除一个数字出现两次外,其他所有数字只出现一次。假设你只能对这个数组做一次处理,用一种算法找出重复的那个数字。如果你在运算中使用了辅助的存储方式,那么你能找到不用这种方式的算法吗?


方法一使用辅助的存储方式,该选择何种存储方式呢?可使用hash的存储方式,以1到1000作为hash表的索引,遍历原数组,统计各数字出现的个数并存储到以该数字为索引值的hash表中,若某个hash[x]的值为2则退出循环,x就是重复出现两次的数字。时间复杂度最坏是O(n)。优点:高效率,缺点:消耗的内存空间过大。

代码如下所示:

 int hash[7]={0};      for(int i=0;i<7;++i){          if(++hash[a[i]]==2){              cout<<"result:"<<a[i];              break;          }      }  

这个方法是本人认为解这里问题的比较好的一种方法,对于问题的变形也具有一定的鲁棒性。比如题目改变成:在一个数组中有1000个数字,数字范围是1到1000,其中只有一个是重复的剩下的都不重复。


方法二,采用异或的方式来求取

思想:1001个数异或结果与1-1000异或的结果再做异或,得出的值即位所求。
原理:
设重复数为A,其余999个数异或结果为B。1001个数异或结果为A^A^B。1-1000异或结果为A^B。由于异或满足交换律和结合律,
则有 (A^B)^(A^A^B)=A^B^B=A

代码如下:

 int a[7]={1,4,5,6,2,3,5};    int i=0,j=0;    int b[6]={1,4,6,2,3,5};    int temp=a[0];    for(i=1;i<7;++i){        temp=temp^a[i];    }    int temp2=b[0];    for(j=1;j<6;++j){        temp2=temp2^a[j];    }    int result = temp^temp2;    cout<<"result:"<<result;


用异或的方法解决此类问题可扩展性也非常好,比如,当题目变形为:在一个数组中只有一个数是不重复的剩余的数都出现了两次,现在求不重复的那个数。

思路:异或中两个相同的数相异或结果为0,0与其他数异或都是其他数。代码如下:

 int a[5]={5,4,5,1,4};      int i=0,j=0;      int temp=a[0];      for(i=1;i<5;++i){          temp=temp^a[i];      }      cout<<"result:"<<temp;


方法三,求和法

这个是完全的数学思想的一种方法:想将原数组S1的所有元素的加起来,然后再将S2={1,2,...,1000}折1000个数的所有元素加起来,最后做减法就能得到出现仅两次的那个数了。


但是这个方法的局限性很强,比如将题目变形一下:在一个数组中有1000个数字,数字范围是1到1000,其中只有一个是重复的剩下的都不重复(也就是在这1000个数据中有一个数出现了两次,有一个数一次都没出现),若是求那个重复的数字是多少?此时用这个方法就行不通了。此时使用方法一能够解决。


若是求那个没出现的数字是多少,就需要方法一和方法三合作求出了。先用方法一求出重复的数字x,然后sum(s2)-(sum(s1)-x);其中s1是输入的数组,s2是1到1000的数组。


这个题目只是这类题目中的一个,变形的有很多。















1 0
原创粉丝点击