题目:
读入2n个数字,其中,除了有两个数字是单独出现外,剩下任何一个数字出现次数都是偶数个,请写出算法找出这两个数字并输出
读入样例:
8
1 3 4 5 9 1 4 3
输出:
5 9
思路1:看到这道题目,第一反应就是for循环枚举一遍,然后统计每个数字出现的次数,最后输出出现次数是奇数次的:
<span style="font-size:14px;">map<int,int> num;
for (int i=1;i<=n;i++)
{
cin>>arr[i];
num[arr[i]]++;
}
for (int i=1;i<=n;i++)
if (num[arr[i]]==1)
cout<<arr[i]<<endl;</span>
这样做,时间复杂度是O(NlogN)的,空间复杂度是O(N)的,已经是一个不错的算法,如果使用哈希表来写,时间复杂度可以降低到O(N)。
思路2:先来考虑一个更简单的问题,读入2n+1个数字,其中只有一个数字出现了1次,剩下的都是偶数次。
这样子的话,题目被简化了很多,这个时候怎么做呢?可以考虑这样一个神奇的操作:^
a^a=0,b^a^b^a=0,对于样例来说(假设没有9那个数字):1^3^4^5^1^4^3=5,3和3,4和4,1和1互相都^成了0,剩下的5就是唯一单独出现的那个数字。
当孤立的数字成了两个的时候,^又能带来什么呢,1^3^4^5^9^1^4^3=12
在二进制下
5=0101 , 9=1001 5^9=0101^1001=1100=12
由异或的性质可以知道,结果里面两个位置上的1,说明这两个数字在这两位上是不同的,因此,我们可以根据其中任意一位上是0或者1,把所有的数字分成两拨:
4 5 4……二进制下第三位是1
1 3 9 1 3……二进制下第三位是0
这样,再对他们分别进行异或,就能得到结果5和9!
<span style="font-size:14px;">int num=0;
for (int i=1;i<=n;i++) num^=arr[i];
int now=1;
for (int i=1;;i++)
{
if ((num&now)>0)
break;
now*=2;
}
int ans1=0,ans2=0;
for (int i=1;i<=n;i++)
if ((arr[i]&now)>0)
ans1^=arr[i];
else
ans2^=arr[i];
cout<<ans1<<' '<<ans2<<endl;</span>