在一个长度为n的整形数组a里,除了三个数字只出现一次外,其他的数字都出现了2次。请写程序输出任意一个只出现一次的数字,程序时间和空间复杂度越小越好。
例如: a = {1,3,7,9,5,9,4,3,6,1,7},输出4或5或6
例如: a = {1,3,7,9,5,9,4,3,6,1,7},输出4或5或6
算法流程:
(1). f(x) = x&(-x) ----->该函数可以得出x从右边开始出现1的位置,比如 f(0x1100) = 0x0100
(2). x = a^b^c
(3).
flag = f(x^a)^f(x^b)^f(x^c) 结果必有一位是1,因为flag不可能为0
,因此flag在某一位上一定为1
证明:
f(x^a),f(x^b),f(x^c)分别表示
x^a, x^b, x^c的右边第一个1的位置,并且
x^a = b^c, x^b=a^c,x^c=a^b
假设flag的值为0,那么
f(x^a),f(x^b),f(x^c)都为0,即
x^a, x^b, x^c为0,那么a=b=c矛盾
(4). f(x^a)^f(x^b)^f(x^c)的第m位为1,则f(x^a), f(x^b), f(x^c)必有1个或者3个第m位为1,因为只能是 0^0^1=1或者1^1^1=1
(5). x^a, x^b, x^c只有一个第m位为1
证明(5) 由于(4)得出,
f(x^a), f(x^b), f(x^c)
必有1个或者3个第m位为1,(结论1)因此
x^a, x^b, x^c的第m位最多是1个为1或者三个为1。因为f(x)表示x的右边第一个为1的位置,那么f(x)值的第m位为1(f(x)中只能有一个1),也就表示x的第m位也为1.因此f(x)为1的位置和x为1的位置是对应的。假设
x^a, x^b, x^c
有三个在m位上为1。
1> 如果 x(m) =1 --------->x(m)表示x的m位,下同。
那么必有:a(m) = 0,b(m)=0, c(m)=0.
并且x(m) = a(m)^b(m)^c(m) = 0 矛盾。
2>如果 x(m) = 0:
那么必有:a(m) = 1,b(m)= 1,c(m) = 1
并且x(m) = a(m)^b(m)^c(m) = 1 矛盾。
综上所述,
x^a, x^b, x^c
有三个在m位上为1的假设是不成立的。因此只能有一个。
(6)flag = f (
f(x^a)^f(x^b)^f(x^c))
(7)如果f(x^i) = flag的数都在一组里面,并且包含了所求的值,最后对这组值求异或即得结果。
代码如下:
int f(int x)
{
return x&(-x);
}
int find(int [] datas)
{
int len=datas.length;
int x = 0;
for(int i=0;i<len;i++){
x ^= datas[i];
}
int flag = 0;
for(int i=0;i<len;i++){
flag ^= f(x^datas[i]);
}
int b=0;
for(int i=0;i<len;i++){
if(f(x^datas[i]) == f(flag))
b ^= datas[i];
}
return b;
}
参考文章:
数组中N(n=1,2,3)个只出现一次的数字
对文章中的算法进行证明,并且还该掉了一处错误的地方(如果改得不对,还望指正),然后使用java实现算法,代码是参考hackbuteer1的2013年小米校园招聘笔试题