汉明距离

本文转载自文章“汉明距离及其高效计算方法”,记录笔记。

汉明距离#

在信息论中,两个等长字符串之间的汉明距离(英语:Hamming distance)是两个字符串对应位置的不同字符的个数。换句话说,它就是将⼀个字符串变换成另外⼀个字符串所需要替换的字符个数

对于两个数字来说,汉明距离就是转成⼆进制后,对应的位置值不相同的个数。例如,假设有两个⼗进制数 a=93 和 b=73 ,如果将这两个数⽤⼆ 进制表⽰的话,有 a=1011101 、 b=1001001 ,可以看出,⼆者的从右往左数的第3位、第5位不同(从1开始数),因此, a 和 b 的汉明距离是2

汉明距离是以理查德·卫斯⾥·汉明的名字命名的。在通信传输过程中,累计定长⼆进制字中发⽣翻转的错误数据位,所以它也被称为信号距离。 汉明距离在包括信息论、编码理论、密码学等领域都有应⽤。

  • 信号距离,就是传输前后信息若发生翻转,出现错误,则出现的错误数据位数是信号距离。

如何计算#

既然⽬标是计算两个⼆进制数的对应位的值不同的个数,我们⾃然会联想到异或运算。因为异或运算的原则就是相同为0,不同为1。因此,通过 计算 c=aXORb ,然后统计c中的各⼆进制位出现的 1 的次数,就能得到汉明距离了。

例如:aXORb=(1011101)2XOR(1001001)2=(0010100)2,汉明距离是2

一眼就能看出(0010100)2中有2个1,那计算机怎么识别呢?

即如何统计 c 的⼆进制格式中 1 出现的次数?

方法1#

我们可以将 c 逐步右移,并且每次将其和 1 (假设位宽是8,也就是 00000001 )进⾏与运算,以检测最右边的位是否为1(如果最右边的位是 1 ,那么与运算的结果肯定也是1 ,否则为 0 )。⼀个循环下来,就能检测出 c 中 1 出现的次数了。

例如:

image-20220906204800912

程序实现:

def hammingDistance(x, y):
    xor = x ^ y #先异或
    distance = 0
    # 每次右移,最左边都会补零,因此截⽌条件是xor已经是⼀个零值了
    while xor:
        if xor & 1:
        	distance = distance + 1 #检测到1
        xor = xor >> 1 # 右移
    return distance

方法2#

上述算法是⼀个很符合直觉的算法,但需要遍历所有的位。这⾥给出⼀个更精巧的思路,可以提⾼性能。

布莱恩.尼克根算法

我们先观察如下⼀个现象:对于任意⼀个⾮零的⼆进制数 a (将其看作⽆符号数),考虑 a 和 a-1 的关系。由于 a ⾮零,那么 a 中总有⼀些位为1 。假设 a 中最低位的 1 处于从右向左数的第 N 位。那么, a 的第 N 位以及第 N 位以后的每⼀位的值和 a-1 的第 N 位及第 N 位以后的每⼀位 的值均不同

举例,我们以8位数来描述。假设 a=10010000 ,根据上述描述,从右往左数的第⼀个 1 出现在第 5 位,那么有 N=5 。同时可 以计算出 a-1=10001111 ,可以看到,从第 N 位开始(从右开始), a 的后缀是 10000 ,⽽ a-1 的后缀是 01111 。满⾜上述描述的现象。

进⼀步地,我们可以发现,如果对 a 和 a-1 进⾏与操作,就会直接消去位于最后⼀位,也就是第 N 位的 1 。还以上⾯的 a 为例, a & (a1)=10000000 。可以看到,我们不需要遍历,⽽是通过⼀次运算,就可以把 a 中的最后⼀个 1 消掉。如果我们⼀直重复这项操作,那么 a ⾥有多少 个 1 ,我们就仅需要多少次 a & (a-1) 的操作,就能把 a 化为 0 了。⽽这个操作的次数正是我们所要求的。

再举例看⼀下这个过程。假设⼀个数 x=10010001 ,那么有:

x = 10010001, x-1 = 10010000, y = x & (x - 1) = 10010000

y = 10010000, y-1 = 10001111, z = y & (y - 1) = 10000000

z = 10000000, z-1 = 01111111, z & (z - 1) = 00000000

x ⾥有 3 个 1 ,经过上述过程,只需要 3 次操作,就能得知 x 中有多少个 1 。⽽如果使⽤遍历的⽅法的话,需要 8 次操作才⾏。

改进的求汉明距离的代码如下:

def hammingDistance(x, y):
    xor = x ^ y #先异或
    distance = 0
    while xor:
        distance = distance + 1
        xor = xor & (xor - 1)
    return distance

这也是leetcode上的⼀道热题#461,⼤家可以参考。

image-20220906211956980

  • 可以看出方法2更快。

image-20220906212549507

作者:Hang Shao

出处:https://www.cnblogs.com/pam-sh/p/16663399.html

版权:本作品采用「知识共享」许可协议进行许可。

声明:欢迎交流! 原文链接 ,如有问题,可邮件(mir_soh@163.com)咨询.

posted @   PamShao  阅读(2111)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2021-09-06 C++:随机数生成
2021-09-06 C++:typedef 与 #define 的区别
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu