做了LeeCode一道简单题,计算汉明距离https://leetcode-cn.com/problems/hamming-distance/
想到位运算不要太简单(Python一行出答案),问题是没想到、、
补课开始
一、题目介绍
二、手算思路
三、位运算求解
四、位与或,逻辑与或
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x 和 y,计算它们之间的汉明距离。
注意:
0 ≤ x, y < 231.示例:
输入: x = 1, y = 4
输出: 2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑上面的箭头指出了对应二进制位不同的位置。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/hamming-distance
(只是想让花时间写的东西有点用,顺便展示一下本人劣质的代码供大佬们审阅,可跳过)
为方便理解,设两数为x,y,思路如下:
- 根据手算规则,首先对两数中较大的一个数(比如x)求其二进制位数n(getMaximumBit函数),得到最大位数number(从第0位开始)
- 从2 ^ number 次方开始,对两个数分别进行减法操作,如差值大于0则说明二进制中当前位为1,否则为0
- 对两数差值进行比较,当且仅当两数差值在0两侧时当前二进制位不相等,汉明距离 distance+1
- 重复上述步骤,直到两数的值均等于0时,循环结束
举例说明:
代码如下:
class Solution {
public int hammingDistance(double x, double y) {
int number = getMaximumBit(x,y);
int distance = 0;
for (int i=number; i>=0; i--){
if (x-Math.pow(2,i) >= 0 && y-Math.pow(2,i) >= 0){
x = x-Math.pow(2,i);
y = y-Math.pow(2,i);
continue;
}
if (x-Math.pow(2,i) >= 0 && y-Math.pow(2,i) <= 0){
x = x-Math.pow(2,i);
distance++;
continue;
}
if (x-Math.pow(2,i) <= 0 && y-Math.pow(2,i) >= 0){
y = y-Math.pow(2,i);
distance++;
continue;
}
if (x == 0 && y== 0){
break;
}
}
return distance;
}
//判断二进制转换后的最高位数
public int getMaximumBit(double a, double b){
if (a >= b){
for (int i=0; i<=a; i++){
if (Math.pow(2,i) > a){
return i-1;
}
}
}
if (a < b){
for (int i=0; i<=b; i++){
if (Math.pow(2,i) > b){
return i-1;
}
}
}
return 0;
}
}
这里需要使用幂运算,使用的是Math.pow()方法,注意该方法返回的值是double类型。由于不知道测试用例有多大,这里直接把int全换成double了,否则强制类型转换应该也是可以的。
直接对两个数的二进制代码进行按位比较即可,代码如下:
class Solution{
public int hammingDistance(int x, int y) {
int cnt = 0;
while (x != 0 || y != 0) {
if ((x & 1) != (y & 1)) {
cnt++;
}
x >>= 1;
y >>= 1;
}
return cnt;
}
}
循环跳出条件依旧是两数全为0的情况。移位运算没有问题,主要还是对于 if 的判断条件有点云里雾里,于是自己编了段程序解释一下:
public class Main {
//与运算
public static void andOperation(int a, int b){
int temp = a & b;
String res = a + " & " + b + " = " + temp;
System.out.println(res);
}
//或运算
public static void orOperation(int a, int b){
int temp = a | b;
String res = a + " | " + b + " = " + temp;
System.out.println(res);
}
//测试一下
public static void main(String[] args) {
System.out.println("----------与运算:----------");
andOperation(3,5);
andOperation(21,32);
andOperation(32,21);
System.out.println("----------或运算:----------");
orOperation(7,4);
orOperation(29,45);
orOperation(45,29);
System.out.println("----------运算结束----------");
}
}
运行结果:
可见对两数求位运算是将两数先转换成二进制,然后根据与、或的关系进行逐位比较。
以第一个式子 3 & 5 为例:
- 3的二进制11,5的二进制101;前者位数较少,高位补0,得 011 与 101。
- 将 011 与 101 进行与运算,结果 001。
- 将结果转化为十进制,得 1。
其他计算同理,与或运算满足交换律。
逻辑与或(符号表示为&,|):
- 将两数转化为二进制进行对应位的逐位比较,并将结果以十进制形式返回。
- 逻辑与:当且仅当对应二进制位均为 1 时,结果为1。
- 逻辑或:当且仅当对应二进制位均为 0 时,结果为0。
短路与或(符号表示为&&、||):
- 功能上与逻辑与或类似,但更灵活。
- 短路与:当且仅当两边均为 true 时,结果为 true。
- 短路或:当且仅当两边均为 false 时,结果为 false。
- 如果判断语句很长,在当前情况下足以判断整体条件的 true 或 false 时,将舍弃之后的判断,直接输出答案。
- 例如对于 if(a>1 || a==3)。当 a > 1 时,由于中间是短路或 || 符号,只要有一个为 true 即整体 true,程序只会执行前半部分;而对于if(a>1 && a==3),同样是 a > 1 的条件,则需要判定a的具体值是否为 3 才能确定结果。