题目1351:数组中只出现一次的数字
-
题目描述:
- 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
-
输入:
-
每个测试案例包括两行:第一行包含一个整数n,表示数组大小。2<=n <= 10^6。第二行包含n个整数,表示数组元素,元素均为int。
-
输出:
- 对应每个测试案例,输出数组中只出现一次的两个数。输出的数字从小到大的顺序。
-
样例输入:
-
8 2 4 3 6 3 2 5 5
-
样例输出:
-
4 6
算法分析
假设a,b为数组中只出现了一次的两个数,
由于相同的两个数进行 按位异或 运算得到 0, 而0 和任何数值进行 按位异或 得到该数本身。
对数组中所有数值进行异或运算,而a,b两数只出现了一次,那么最终的结果等于 a按位异或b,得到andr
可知andr上必有一位为1,并且 a,b两数在该位上不同(否者 按位异或后就得0)。
我们根据andr上该1位对数组中的所有数值进行分类,该位为1的为1组,为0的为1组。
这样就转化为了 一个数组只有一个数出现一次,其它数出现两次的问题。
对两组数字分别进行 按位异或 运算,就可以得到要求的两个不同数。
在求andr上为1的位时有个技巧 andr = andr &(-andr)
-andr是通过对andr按位取反加1所得, andr & (-andr)就可以得到最低位的1所在位
源程序
输入输出 用scanf print,否则程序会超时
#include <iostream>
#include <stdio.h>
int nums[1000000];
int main()
{
int n=0 ;
int andr = 0;
while(scanf("%d",&n) != EOF){
int i = 0;
andr = 0;
while(i<n){
scanf("%d",nums+i);
andr^=nums[i];
i++;
}
andr = andr &(-andr);
i = 0;
int num1=0;
int num2=0;
while(i<n){
if(nums[i]&andr)
num1^=nums[i];
else
num2^=nums[i];
i++;
}
if(num1<num2)
std::cout<<num1<<" "<<num2<<std::endl;
else
std::cout<<num2<<" "<<num1<<std::endl;
}
return 0;
}