题目如下

两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。

给你两个整数 x 和 y,计算并返回它们之间的汉明距离。

1014-汉明距离-编程之家

解题思路

汉明距离广泛应用于多个领域。在编码理论中用于错误检测,在信息论中量化字符串之间的差异。

两个整数之间的汉明距离是对应位置上数字不同的位数。

根据以上定义,我们使用异或运算,记为 ⊕,当且仅当输入位不同时输出为 1。

1014-汉明距离-编程之家
计算 x 和 y 之间的汉明距离,可以先计算 x⊕y,然后统计结果中等于 1 的位数。

现在,原始问题转换为位计数问题。位计数有多种思路,将在下面的方法中介绍。

方法一:内置位计数功能

思路及算法
大多数编程语言都内置了计算二进制表达中 1 的数量的函数。在工程中,我们应该直接使用内置函数。

class Solution 
{
public:int hammingDistance(int x, int y) {return __builtin_popcount(x ^ y);}
};

复杂度分析
时间复杂度:O(1)。不同语言的实现方法不一,我们可以近似认为其时间复杂度为 O(1)。
空间复杂度:O(1)。

方法二:移位实现位计数

思路及算法

在锻炼算法能力时,重复造轮子是不可避免的,也是应当的。因此读者们也需要尝试使用各种方法自己实现几个具有位计数功能的函数。本方法将使用位运算中移位的操作实现位计数功能。
1014-汉明距离-编程之家

具体地,记s=x⊕y,我们可以不断地检查 s 的最低位,如果最低位为 1,那么令计数器加一,然后我们令 s 整体右移一位,这样 s 的最低位将被舍去,原本的次低位就变成了新的最低位。我们重复这个过程直到 s=0 为止。这样计数器中就累计了 s 的二进制表示中 1 的数量。

class Solution 
{
public:int hammingDistance(int x, int y) {int s = x ^ y, ret = 0;while (s) {ret += s & 1;s >>= 1;}return ret;}
};

复杂度分析
时间复杂度:O(logC),其中 C 是元素的数据范围,在本题中logC=log2
31 =31。
空间复杂度:O(1)。

方法三:Brian Kernighan 算法

思路及算法

在方法二中,对于 s=(10001100) 2的情况,我们需要循环右移 8 次才能得到答案。而实际上如果我们可以跳过两个 1 之间的 0,直接对 1 进行计数,那么就只需要循环 3 次即可。

我们可以使用 Brian Kernighan 算法进行优化,具体地,该算法可以被描述为这样一个结论:记f(x) 表示 x 和 x−1 进行与运算所得的结果(即f(x)=x & (x−1)),那么 f(x) 恰为 x 删去其二进制表示中最右侧的 1 的结果。
1014-汉明距离-编程之家
基于该算法,当我们计算出s=x⊕y,只需要不断让s=f(s),直到 s=0s=0 即可。这样每循环一次,s 都会删去其二进制表示中最右侧的 1,最终循环的次数即为 s 的二进制表示中 1 的数量。

class Solution 
{
public:int hammingDistance(int x, int y) {int s = x ^ y, ret = 0;while (s) {s &= s - 1;ret++;}return ret;}
};

复杂度分析
时间复杂度:O(logC),其中 C 是元素的数据范围,在本题中 logC=log2
31 =31。
空间复杂度:O(1)。