题目如下:
Description |
||
海明距离是在指二进制情况下,一个整数变成另外一个整数需要翻转的位数。比如2转换到3需要翻转1位,所以2到3的海明距离是1。给你两个正整数x和y,(x,y<=1,000,000,000)求它们的海明距离。 输入 第一行是一个整数N,表示样例的个数。以后每行两个整数x和y。 输出 每行输出一个整数,及对应样例的结果。
|
||
Sample Input |
||
2 1 2 4 7 |
||
Sample Output |
||
2 2 |
分析思路:
简单来说就是一个多样例输入,对于每一组输入都转化成二进制然后进行逻辑上的异或运算,即比较两个二进制数对应的每一位,同为0或同为1则返回0,一个为0一个为1则返回1。例如2的二进制表示为……00000010,3的二进制表示为……00000011,他们进行异或运算的结果为……00000001,也就是最后一位不同需要“翻转”。所以海明距离实际就就是看两个数进行二进制的异或运算后为1的位数有几位。
核心问题:
有了上面的思路,现在的问题就是要怎么把输入的十进制的数转化为二进制进行异或运算呢?开始想的是把十进制数通过取模运算一步步转换成二进制数储存在数组中,然后利用循环分别比较每一位,两个数在那一位上的数不相同则计数+1。
后来才回忆起来C语言里提供了“位运算符”,可以直接通过a^b对这两个十进制数的二进制形式进行异或运算(不需要自己转换进制)。详情可参考【http://blog.csdn.net/chen825919148/article/details/8049069】
运算符 | 作用 |
& | 位逻辑与:按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。 例如:9&5可写算式如下: 00001001 (9的二进制补码)&00000101 (5的二进制补码) 00000001 (1的二进制补码)可见9&5=1。 |
| | 位逻辑或:按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。 例如:9|5可写算式如下: 00001001|00000101=00001101 (十进制为13)可见9|5=13 |
^ | 位逻辑异或 :按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现,例如 9^5可写成算式如下: 00001001^00000101=00001100 (十进制为12) |
~ | 位逻辑反 :求反运算符~为单目运算符,具有右结合性。 其功能是对参与运算的数的各二进位按位求反。例如~9的运算为: ~(0000000000001001)结果为:1111111111110110 |
>> | 右移:右移运算符“>>”是双目运算符。其功能是把“>> ”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数。例如:设 a=15,a>>2 表示把000001111右移为00000011(十进制3)。应该说明的是,对于有符号数,在右移时,符号位将随同移动。当为正数时, 最高位补0,而为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定。 |
<< | 左移:左移运算符“<<”是双目运算符。其功能把“<< ”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0。例如: a<<4 指把a的各二进位向左移动4位。如a=00000011(十进制3),左移4位后为00110000(十进制48)。 |
最后附上我的程序源码:
1 #include<stdio.h> 2 int main() 3 { 4 int n,i,a,b; 5 scanf("%d",&n); 6 for(i=1;i<=n;i++) 7 { 8 scanf("%d%d",&a,&b); 9 a^=b; //a,b的异或运算,把运算结果储存在a中; 10 b=0; //把b重置为0,用于计数; 11 while(a) 12 { 13 if(a&1) //二进制a于(二进制)...00001的且运算,同1为1,其余为0;即异或运算后的结果最后一位为1时计数+1 14 b++; 15 a>>=1; //对a进行右移位运算,去掉最低位,下一次循环比较上一位,直至a的值为0; 16 } 17 printf("%d ",b); //输出异或运算后结果为1的位数有几位,即两个数的海明距离; 18 } 19 return 0; 20 }