汉明距离 图解题解
这道题到底在问什么
- 输入
- x = 1, y = 4
- 输出
- 2
最优解:为什么这么做
一句话答案:LeetCode 461 汉明距离的标准解是异或加 Brian Kernighan 数 1:先算 n = x ^ y,两数所有不同的位在 n 里恰好变成 1;再循环执行 n &= (n - 1),每次精确抹掉最低位的一个 1,循环的次数就是汉明距离。时间 O(k)(k 是不同位的个数,最多 32),空间 O(1)。
汉明距离在问什么
给两个整数 x 和 y,问它们的二进制表示里有多少个「对应位置」上的位不一样,这个数目就叫汉明距离。比如 x = 1(二进制 001)、y = 4(二进制 100),第 0 位和第 2 位都不同,距离为 2。注意比的是同一位号上的两个位——把两个数各自的 1 数出来相减是不对的,位置错开的 1 互相抵不了账。
为什么第一步是把 x 和 y 异或
直觉做法是逐位对比:对每个位号 b 取出 (x >> b) & 1 和 (y >> b) & 1 比较,不同就计数。能做对,但其实二进制世界里早有一个运算天生就在做「逐位比不同」——异或:两位不同得 1,相同得 0。一句 n = x ^ y,32 个位置的对比一次做完,所有不同的位在 n 里被点亮成 1,问题瞬间化简成「数 n 里有几个 1」,也就是求 n 的 popcount(位计数)。
n 与 n-1 按位与为什么恰好抹掉一个 1
数 1 的经典技巧是 Brian Kernighan 算法:只要 n 不为 0,就执行 n &= (n - 1),每执行一次计数加一,n 归零时计数就是 1 的个数。它成立的原理在减 1 的借位上:n - 1 会把 n 最低位的那个 1 变成 0,并把它右边的 0 全部变成 1,而更高的位纹丝不动。再和 n 按位与,最低位那个 1 及其右边全部归零,高位原样保留——一次操作,精确消掉恰好一个 1,不多不少。
所以循环体每转一圈,n 里的 1 就少一个;转了几圈,n 里原本就有几个 1。计数和消位绑在同一个动作里,这就是它优雅的地方。
Kernighan 比逐位右移扫描快在哪
逐位扫描(n & 1 配合 n >>= 1)要一直移到最高的有效位,循环次数由位宽决定,32 位整数就是最多 32 圈,跟 1 的多少无关。Kernighan 的循环次数只等于 1 的个数:x ^ y 里只有 3 个 1,就只转 3 圈。最坏情形两者同阶,但稀疏时 Kernighan 明显省。工程上还有更快的路——很多语言和 CPU 提供内建 popcount(比如 C++ 的 __builtin_popcount),一条指令出结果;面试则更看重你能讲清 n & (n - 1) 的借位原理。
复杂度与一个负数陷阱
时间 O(k),k 是 x ^ y 中 1 的个数,上限是整数位宽(32),所以也可以说 O(1);空间 O(1),全程只有 n 和 count 两个变量。
一个值得记住的陷阱:如果用逐位右移的写法去数负数,在做算术右移的语言里高位会不断补 1,循环永远到不了 0,直接死循环;要改用逻辑右移或先转成无符号数。本题约束 x、y 都非负,踩不到这个坑,但换个含负数的位运算题它就会咬人。
▶ 动画逐步走查(共 23 步)——想跟着动画一帧帧对照就展开
- 3思路一句话:不同位 → 异或点亮成 1 → 数 1 的个数。数 1 用 n &= (n-1) 逐个抹最低位 1。下面用 x=438、y=220 一步步演给你看。
- 4先把 x、y、x^y 三行二进制摆出来(共 9 位,高位在左)。x^y 还没算,下面从最高位开始,逐位对比 x、y 是否相同。
- 5第 8 位:x 是 1、y 是 0,两位不同 → 异或得 1(绿色点亮)。这就是一处「不同的位」。
- 6第 7 位:x 是 1、y 是 1,两位相同 → 异或得 0,这一位不算「不同」。
- 7第 6 位:x 是 0、y 是 1,两位不同 → 异或得 1(绿色点亮)。这就是一处「不同的位」。
- 8第 5 位:x 是 1、y 是 0,两位不同 → 异或得 1(绿色点亮)。这就是一处「不同的位」。
- 9第 4 位:x 是 1、y 是 1,两位相同 → 异或得 0,这一位不算「不同」。
- 10第 3 位:x 是 0、y 是 1,两位不同 → 异或得 1(绿色点亮)。这就是一处「不同的位」。
- 11第 2 位:x 是 1、y 是 1,两位相同 → 异或得 0,这一位不算「不同」。
- 12第 1 位:x 是 1、y 是 0,两位不同 → 异或得 1(绿色点亮)。这就是一处「不同的位」。
- 13第 0 位:x 是 0、y 是 0,两位相同 → 异或得 0,这一位不算「不同」。
- 14x^y 全部算完了:x^y = 362。绿色的就是「不同的位」,一共 5 个 1。下面用 n &= (n-1) 一次抹掉一个 1,数清楚到底几个。
- 15n 还不是 0,说明里面还有 1。最低位的那个 1 在第 1 位(紫框标出)。n-1 会把它及它右边变样,n &= (n-1) 正好把这个 1 抹掉。
- 16这个 1 被抹掉,计数变成 1(灰色是已数过的位)。n 还不是 0,回到上一步继续消下一个最低位的 1。
- 17n 还不是 0,说明里面还有 1。最低位的那个 1 在第 3 位(紫框标出)。n-1 会把它及它右边变样,n &= (n-1) 正好把这个 1 抹掉。
- 18这个 1 被抹掉,计数变成 2(灰色是已数过的位)。n 还不是 0,回到上一步继续消下一个最低位的 1。
- 19n 还不是 0,说明里面还有 1。最低位的那个 1 在第 5 位(紫框标出)。n-1 会把它及它右边变样,n &= (n-1) 正好把这个 1 抹掉。
- 20这个 1 被抹掉,计数变成 3(灰色是已数过的位)。n 还不是 0,回到上一步继续消下一个最低位的 1。
- 21n 还不是 0,说明里面还有 1。最低位的那个 1 在第 6 位(紫框标出)。n-1 会把它及它右边变样,n &= (n-1) 正好把这个 1 抹掉。
- 22这个 1 被抹掉,计数变成 4(灰色是已数过的位)。n 还不是 0,回到上一步继续消下一个最低位的 1。
- 23n 还不是 0,说明里面还有 1。最低位的那个 1 在第 8 位(紫框标出)。n-1 会把它及它右边变样,n &= (n-1) 正好把这个 1 抹掉。
- 24这个 1 被抹掉,计数变成 5。n 现在是 0,再也没有 1 了 —— 一共数了 5 个 1,这就是汉明距离!
- 25n 被消成全 0,一共消了 5 次,说明 x^y 里有 5 个 1。汉明距离(x 与 y 不同的位数)= 5。
⚠️ 容易写错的地方
✗ 错:逐位比 x、y 时忘了对齐到同一位
✓ 对:同一位号 b 上比 (x>>b)&1 与 (y>>b)&1
汉明距离比的是「对应位」
✗ 错:用 n & 1 配合 n >> 1 一定要循环到 0
✓ 对:能数对但要扫满最高有效位
Kernighan 只转「1 的个数」次更省
✗ 错:负数右移用算术移位陷入死循环
✓ 对:Python/逻辑右移或先转无符号
高位补 1 会数不完;本题 x,y≥0 不踩,但要知道
完整代码(Python / C++ / Java)
Python
def hammingDistance(x, y):
n = x ^ y # 异或:不同的位变 1
count = 0
while n:
n &= n - 1 # 抹掉最低位的一个 1
count += 1
return countC++
int hammingDistance(int x, int y) {
int n = x ^ y; // 异或:不同的位变 1
int count = 0;
while (n) {
n &= (n - 1); // 抹掉最低位的一个 1
++count;
}
return count;
}Java
public int hammingDistance(int x, int y) {
int n = x ^ y; // 异或:不同的位变 1
int count = 0;
while (n != 0) {
n &= (n - 1); // 抹掉最低位的一个 1
count++;
}
return count;
}复杂度
时间
O(k)
k = x^y 里 1 的个数;Kernighan 只循环「1 的个数」次(最多 32 次)
空间
O(1)
只用了 n、count 两个变量
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 汉明距离 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
n &= (n-1) 为什么能精确抹掉最低位的一个 1?+
n-1 会把 n 最低位的那个 1 变成 0、并把它右边原本的 0 全变成 1;再与 n 按位与,最低位 1 及右边都归 0,正好只抹掉了这一个 1,其余高位的 1 不受影响。
除了 Kernighan,还能怎么数 1?+
可以逐位 n & 1 再 n >>= 1 扫满位宽;或用查表/分治位计数(如 popcount);很多语言/CPU 有内建 popcount 指令(如 C++ __builtin_popcount),一条指令出结果。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 汉明距离 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。