题目中包括三个小的问题,由简单到复杂:
1,如果只有一个出现一次,考察到异或的性质,就是如果同一个数字和自己异或的活结果为零,那么循环遍历一遍数组,将数组中的元素全部做异或运算,那么出现两次的数字全部异或掉了,得到的结果就是只出现一次的那个数字。
下面首先给这部分的程序和实例分析:
1 #include<stdio.h> 2 #include<stdlib.h> 3 int main(int argv,char* argc[]) 4 { 5 int index; 6 int res=0; 7 int arr[11]={0}; 8 for(index=0;index<11;index++) 9 { 10 scanf("%d",&arr[index]); 11 } 12 for(index=0;index<11;index++) 13 { 14 res^=arr[index]; 15 } 16 printf("这个数是%d\n",res); 17 system("pause"); 18 }
2,如果有两个只出现一次的数字,设定为a,b。也是应用异或,但是数组元素全部异或的结果x=a^b,因为a,b是不相同的数字,因此x肯定不为0。对于x,从低位到高位开始,找到第一个bit位为1的位置设定为第m位,这个第m位的bit肯定来自a或者来自b,不可能同时a,b的第m位(从低到高位)都为1。这样,就可以根据这个第m位就可以把数组分为两个部分,一组为第m位为0,一组为第m位为1.这样,就把问题分解成了求两个数组中只出现一次的数字了。
下面首先给这部分的程序和实例分析:
1 #include<stdio.h> 2 int get_first_position(int num) //从低位开始找到第一个位1的bit位 3 { 4 int index=1; 5 int i=0; 6 while(i<32) 7 { 8 if((num&(1<<i))==(1<<i)) 9 break; 10 else 11 { 12 index++; 13 i++; 14 } 15 } 16 return index; 17 } 18 19 int is_bit_one(int num,int index) //判断给定的索引位置的bit位是否为1 20 { 21 num=(num>>index); 22 return num&1; 23 } 24 25 void get_two_unique_num(int *a,int n,int *num1,int *num2) 26 { 27 int exclusive_or_result=0; 28 *num1=0; 29 *num2=0; 30 for(int i=0;i<n;i++) 31 exclusive_or_result^=a[i]; 32 int index=get_first_position(exclusive_or_result); 33 for(i=0;i<n;i++) 34 if(is_bit_one(a[i],index)) 35 (*num1)^=a[i]; 36 for(i=0;i<n;i++) 37 if(!is_bit_one(a[i],index)) 38 (*num2)^=a[i]; 39 } 40 41 void main() 42 { 43 int a[]={2,2,4,4,6,6,3,5}; 44 int num1,num2; 45 get_two_unique_num(a,sizeof(a)/sizeof(int),&num1,&num2); 46 printf("%d\t%d\n",num1,num2); 47 }
3,考虑给定数组中有三个单独出现一次的数字,这个会比有两个的稍微复杂。分步分析,设定这三个数为a,b,c:
(1)将数组中的数字全部异或,得到的结果x=a^b^c,但是x不是a,b,c中的其中一个,假设x=a,那么b^c=0说明b=c,与题目给定的条件矛盾。
(2)设定f(n)可以像2中的那样,从低位开始,找到第一个bit为1的位置,f(x^a),f(x^b),f(x^c)得到的值肯定都不为0,因为x^a,x^b,x^c本身就不为0。f(x^a)^f(x^b)^f(x^c)结果不为0。因为f(x^a)^f(x^b)的结果中可能为0,也可能有两个bit为1。如果假设f(x^c)的结果bit为1的位置与f(x^a)^f(x^b)的其中一个重合,则f(x^a)^f(x^b)^f(x^c)结果中只有1个bit为1,如果不重合的话那么有3个bit位为1。
(3)这便可以推断出f(x^a)^f(x^b)^f(x^c)中至少有一个bit位为1。假设从低位到高位的第mbit位为1.那么可以得出结论x^a,x^b,x^c中有一个或者三个的第m位为1(不可能有两个,因为有两个的话,异或的结果就为0了)。
(4)证明,x^a,x^b,x^c中只有一个第m-bit位为1.假设他们的第m位都为1,那么x的第m位为0,但是x=a^b^c其第m位肯定为1,所以假设不成立。那么相反,假设x的第m位为1,a,b,c的第m位都为0,也不成立,因为x=a^b^c。所以综上所述x^a,x^b,x^c中只有一个第m位为1。那么这个问题就好办了。根据这个第m位找到第一个只出现一次的数字。然后剩下两个就是问题2所描述的问题。下面给出代码:
1 #include<stdio.h> 2 3 int get_first_bit(int num) 4 { 5 return num&~(num-1); 6 } 7 8 void get_two_unique_num(int *a,int n,int *num1,int *num2) 9 { 10 int result_code=0; 11 for(int i=0;i<n;i++) 12 result_code^=a[i]; 13 int diff=get_first_bit(result_code); 14 *num1=0; 15 *num2=0; 16 for(i=0;i<n;i++) 17 { 18 if(a[i]&diff) 19 { 20 (*num1)^=a[i]; 21 } 22 else 23 { 24 (*num2)^=a[i]; 25 } 26 } 27 } 28 29 void get_three_unique_num(int *a,int n,int *num1,int *num2,int *num3) 30 { 31 int result_code=0; 32 for(int i=0;i<n;i++) 33 result_code^=a[i]; 34 int flag=0; 35 for(i=0;i<n;i++) 36 flag^=get_first_bit(result_code^a[i]); 37 flag=get_first_bit(flag); 38 *num1=0; 39 for(i=0;i<n;i++) 40 { 41 if(get_first_bit(result_code^a[i])==flag) 42 { 43 (*num1)^=a[i]; 44 } 45 } 46 for(i=0;i<n;i++) 47 { 48 if(a[i]==(*num1)) 49 { 50 int temp=a[i]; 51 a[i]=a[n-1]; 52 a[n-1]=temp; 53 break; 54 } 55 } 56 get_two_unique_num(a,n-1,num2,num3); 57 } 58 59 void main() 60 { 61 int a[]={2,2,4,4,6,6,3,5,7}; 62 int num1,num2,num3; 63 get_three_unique_num(a,sizeof(a)/sizeof(int),&num1,&num2,&num3); 64 printf("%d\t%d\t%d\n",num1,num2,num3); 65 }