一个数组中只有一个数字出现一次,其余别的数字都出现两次,如何求出这个出现一次的数字?例如数组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);
如果你有更好的方法,不妨在此讨论.