标签:唯一出现一次的三个数
首先在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