一个数组中只有一个数字出现一次,其余别的数字都出现两次,如何求出这个出现一次的数字?例如数组a[11]={1,2,2,3,3,4,4,5,5,6,6},则出现一次的是1,通过异或算法即可求出.
代码如下:
int onediffent(int a[],int n) { int temp=0; for(int i=0;i<n;i++) temp=temp^a[i]; printf("%d\n",temp); }
补充:任何数与零异或等于任何数.任何数与自己相异或为0;
假如问题变成一个数组中有两个数字出现一次,其余别的数字都出现两次,那么如何求出这两个数字呢?
算法思路:首先将数组中的一组数字异或,结果存在temp中,然后计算出temp中最低位出现的位置,然后再和数组中所有的数字相与,这样就将数组分成了两个数组,问题转换为一个数组中只有一个数字出现一次的情况。
代码如下:
int twodiffent(int a[],int n) { int temp,count,i,j,k; temp=a[0]; j=k=0; int b[n],c[n]; for(int i=1;i<n;i++) temp=temp^a[i]; count=1; //求出temp中为1的最低位位置 while(!(temp&1)) { temp=temp>>1; count*=2; } //将两个数字分别分到两个数组中,问题转换为一个数组中只有一个出现一次的数. for(i=0;i<n;i++) { if(a[i]&count==1) b[j++]=a[i]; else c[k++]=a[i]; } onediffent(b,j); onediffent(c,k); }
在算法群里某热心网友不吝赐教得到目前最优解,相对比算法二优化了至少一个世纪<囧>,代码如下:
void solve(int num[],int n) { int x = 0; for(int i = 0; i < n; ++i) { x = x ^ num[i]; } int smallestOne = x & -x; int a = 0; int b = 0; for(int i = 0; i < n; ++i) { if((num[i] & smallestOne) != 0) a = a ^ num[i]; else b = b ^ num[i]; } printf("%d %d\n",a,b); }
该算法中x&-x是算出最低位的1,负数在计算机中是以补码表示,例如4&-4=4,1000&-1000=8 表示数字4中二进制位1最低位是在权为2^2出现,数字1000二进制位1最低位是在权值为2^3出现.算法二中的数组完全没有必要使用,空间复杂度为O(1),时间复杂度O(n);
如果你有更好的方法,不妨在此讨论.
时间: 2024-10-19 14:59:21