LeetCode—461.汉明距离

前言

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

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

  • 根据以上定义,我们使用异或运算,记为 (键盘上"^"符号,在数字6的上边),当且仅当每个输入位不同时输出为1

在这里插入图片描述

  • 计算xy之间的汉明距离,可以先计算 x⊕y,然后统计结果中等于 1 的个数

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

方法一:内置位计数功能

思路及算法

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

Java 中的位操作

static int Integer.bitCount();           // 统计 1 的数量
static int Integer.highestOneBit();      // 获得最高位
static String toBinaryString(int i);     // 转换为二进制表示的字符串

代码:

class Solution {
    public int hammingDistance(int x, int y) {
        return Integer.bitCount(x ^ y);
    }
}

复杂度分析

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

空间复杂度:O(1)。

方法二:移位实现位计数

思路及算法

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

在这里插入图片描述

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

代码:

class Solution {
    public int hammingDistance(int x, int y) {
        int z = x ^ y;
    	int cnt = 0;
    	while(z != 0) {
        	if ((z & 1) == 1) cnt++;//z的最后一位是1
        	z = z >> 1;
   		}
    	return cnt;
    }
}

复杂度分析

时间复杂度:O(log⁡C),其中C是元素的数据范围,在本题中 log⁡C=log⁡ 231=31

空间复杂度:O(1)

方法三:Brian Kernighan算法

思路及算法

在方法二中,对于 s=(10001100)2


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

我们可以使用Brian Kernighan算法进行优化,具体地,该算法可以被描述为这样一个结论:记 f(x)表示xx−1进行与运算所得的结果(即 f(x)=x & (x−1)),那么f(x)恰为x删去其二进制表示中最右侧1的结果。

基于该算法,当我们计算出s=x⊕y,只需要不断让 s=f(s),直到s=0即可。这样每循环一次,s都会删去其二进制表示中最右侧的1,最终循环的次数即为s的二进制表示中1的数量。

代码:

//使用 z&(z-1) 去除 z 位级表示最低的那一位。
public int hammingDistance(int x, int y) {
    int z = x ^ y;
    int cnt = 0;
    while (z != 0) {
        z &= (z - 1);
        cnt++;
    }
    return cnt;
}

复杂度分析

时间复杂度:O(log⁡C),其中C是元素的数据范围,在本题中 log⁡C=log⁡231=31

空间复杂度:O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值