异或的基本原理:异或是二进制间的位运算,相同为0,不同为1,具有可逆性
异或算法的规则,简单地说就是:两值相同,异或操作结果为0,两值不同,异或操作结果为1。并且异或操作本身有一个特点,“X|Y|Y=X”,即一个值X连续两次“异或”另一个值Y,其结果仍然还是X本身,根据这个特点,可以将X视为明文,将Y作为密钥,Z=X|Y就是将常数X进行加密,解密方如果没有Y,则无法由Z还原到X;而如果有Y,则可以通过Z|Y=X|Y|Y=X获得明文X,实现解密,由于这个特点,使异或操作大量被用于数据加密和解密的算法中。
用其他进制表示的数做异或运算时,则应先将他们化为二进制的数,再做运算。(不足的位在前边填0补齐)
一个整型数组里,除了一个或者两个或者三个数字之外,其他数字均出现了两次,请找出只出现一次的数字。要求时间复杂度为O(n),空间复杂度为O(1);
根据异或的特性两个相同的数字异或等于0,而0和一个数字异或等于其本身,所以当进行循环遍历一遍之后得到的结果一定是那个只出现一次的数字。代码实现:
#include<stdio.h>
/*
* 61.找出数组中两个只出现一次的数字
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
*/
int n,a[1000];
void find()
{
if(n<2)
return ;
int i,ab,x,y;
ab=a[0];
for(i=1;i<n;i++)
ab=ab^a[i];//假设两个数为A B 先求出A^B
if(n%2!=0)
printf("%d\n",ab);//只有一个只出现一次的数
else if(ab==0) //没有只出现一次的数,即数均成对出现
printf("NULL\n");
//再求 A^B 二进制中最后一个1的位置K。这样,把数组分为两组,第一组数字的K位置都是1,第二组K位置是0
else
{
//printf("%d\n",ab);
int k=0;
while((ab &1<<k)==0)
k++;
k=(1<<k); //分组,其实不用真的分。 //用K保存,移位后的值,以避频繁移位
//printf("%d\n",k);
x=ab,y=ab;
for(i=0;i<n;i++)
{
if((a[i] &k)==k)
x=x^a[i];
}
for(i=0;i<n;i++)
{
if((a[i]&k)==0)
y=y^a[i];
}
printf("%d%d\n",x,y);
}
}
int main()
{
int i;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
scanf("%d",&a[i]);
find();
}
return 0;
}
按位运算符
整数在计算机中用二进制的位来表示,C语言提供一些运算符可以直接操作整数中的位,称为位运算,这些运算符的操作数都必须是整型的。
& 按位与, | 按位或 , ^ 按位异或
AND (位与&) OR ( 位或| ) XOR ( 位异或^ )
1 & 1 = 1, 1 | 1 = 1, 1 ^ 1 = 0
1 & 0 = 0, 1 | 0 = 1, 1 ^ 0 = 1
0 & 1 = 0, 0 | 1 = 1, 0 ^ 1 = 1
0 & 0 = 0, 0 | 0 = 0, 0 ^ 0 = 0
#include<iostream>
using namespacestd;
/*
* 61.找出数组中两个只出现一次的数字
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
*/
voidfindTwoNumsWithOthersHas2Times(int s[],int len)
{
if(len<2) return;
//假设两个数为A B 先求出A^B
int ab=s[0];
for(int i=1;i<len;++i)
{
ab^=s[i];
}
//再求 A^B 二进制中最后一个1的位置K。这样,把数组分为两组,第一组数字的K位置都是1,第二组K位置是0
int k=0;
while((ab & 1<<k)==0) ++k;
//分组,其实不用真的分。
k=(1<<k); //用K保存,移位后的值,以避频繁移位
int t1=ab,t2=ab;
for(int i=0;i<len;++i)
{
if((s[i]&k)==k)
{
printf("%d ##%d",s[i],k);
t1^=s[i];
}
}
printf("\n");
for (int i = 0; i < len; ++i)
{
if ((s[i] & k ) == 0)
{
printf("%d",s[i]);
t2 ^= s[i];
}
} printf("\n");
cout << t1 << " "<< t2 << endl;
}
int main(){
int s[]={1,2,7,4,5,4,5,2,6,1};
int len=sizeof(s)/sizeof(int);
findTwoNumsWithOthersHas2Times(s,len);
return 0;
}