标签:唯一出现一次的三个数
首先在leetcode上面有这样类似的题,做法大致类似
1,首先是只出现一次的一个数
比较简单,直接全部亦或值就得到了
//只出现一次的一个数 public static int singleNumber1(int[] A) { int res=0; for(int i=0;i<A.length;i++) res^=A[i]; return res; }
则所有的值亦或肯定不为0,设最后的抑或结果为M,找到M从低到高为最先为1的位置,然后根据所有数在该位置为0或者1,分为两组,这样,两个不同的数就被分到两个不同的组,单独对组亦或就得到这两个数
这里由于要移位,所以有个移位函数findOne,函数的主要作用是找出最低位的1,并将数转化为0000010000的形式,例如将8(二进制为00001000-》00001000,假定是8位)
//找到最低位的1,然后转化为返回000010000这样的形式 public static int findOne(int sum){ // 法一:可以返回的要位移的位数 /* int count=0; while(((sum>>count)&1)!=1){ count++; } return count;*/ // 法二 return sum&~(sum-1); //法三: // return sum&(-sum); }
//只出现一次的两个不相等的数 public static int[] singleNumber2(int[] A) { int sum=singleNumber1(A); int []res=new int[2]; int temp=findOne(sum); for (int i = 0; i < A.length; i++) { if((A[i]&temp)!=0){ res[0]^=A[i]; }else res[1]^=A[i]; } return res; }
假定这三个数是a,b,c;x=a^b^c(其他的偶数次的都亦或为0,不管了),
容易证明x不与a,b,c中的任何一个相等(反证,x=a,则x=a^b^c推出b^c=0,推出b=c,矛盾,其他同理)
且a^x b^x c^x都不为0
在上面第2种情况中,介绍了函数findOne(),为了方便下面都简称为f()
考虑f(a^x)^f(b^x)^f(c^x),其他的data^x 都是偶数次
当data不为0的时候,f(data)中只有一位为1,其他位为0,所以上面三个f()值亦或肯定不为0(考虑三个数的1在同一位置,结果不为0;三个1有两个在同一位置,结果还是不为0,三个1互在不同位置,亦或值还是不为0)
则f(a^x)^f(b^x)^f(c^x)结果肯定是非0,f(a^x)^f(b^x)^f(c^x)中考虑最低位(假定是M位置)的1,然后可用m=f(a^x)^f(b^x)^f(c^x)(0000100000形式)
于是f(x^a)^f(x^b)^f(x^c)的结果的二进制中至少有一位是1。假设最后一位是1的位是第m位。那么x^a、x^b、x^c的结果中,有一个或者三个数字的第m位是1。
假若是三个1,a^x b^x c^x 在m位置都是1,则a b c 在m位置与x的m位相反,a b c 在m位的数相同
1,a b c 在m位置都是0,则x在m位置也是0,则a^x b^x c^x在m处也是0,与假设矛盾
2,a b c 在m位置都是1 则x在m处也是1,a^x b^x c^x在m处就是0,与假设矛盾
所以不可能在m处是三个1
所以a^x b^x c^x 在m处只有一个数字为1,根据m=f(a^x)^f(b^x)^f(c^x)(0000100000形式)进行分组,首先找到为1的那个单独在一组,然后从所有数中排除出去,然后剩下的数组中就剩下两个唯一的数了,用第二种情况就oK了,记得所求的是a^x b^x c^x,最后的结果要再亦或一个x
代码如下:
//只出现一次的三个不相等的数 public static int[] singleNumber3(int[] A) { int[] res=new int[3]; int[] A1=new int[A.length-1]; int x=singleNumber1(A); int m=0; int[] value=new int[2]; for (int i = 0; i < A.length; i++) { A[i]=A[i]^x; m^=findOne(A[i]); } m=findOne(m); //再根据A[i]的第m位是否为1,分组(1,0,0) for (int i = 0; i < A.length; i++) { if((A[i]&m)!=0){ res[2]^=A[i]; } } //移除那个数 for (int i = 0,j=0; i < A.length; i++) { if(A[i]!=res[2]) A1[j++]=A[i]; } res[2]=res[2]^x; value=singleNumber2(A1); for (int i = 0; i < 2; i++) { res[i]=value[i]^x; } return res; }
主程序测试代码;
public class test10 { public static void main(String[] args) { int a[]=singleNumber3(new int[]{1, 1, 2, 2, 5,9,12,-4,-4}); for (int i : a) { System.out.println(i); } }
数组中唯一出现一次的一个,两个,三个数,其余数都是偶数次出现(java版本)
标签:唯一出现一次的三个数
原文地址:http://blog.csdn.net/hll174/article/details/45439653