题目背景
做leetcode第461题汉明距离的时候,发现一个很骚的求1的个数的算法,大呼牛逼!
其实题目本身思路不难,就是求异或然后算1个个数,只是没有想到还可以用这么骚的方式来求。
布赖恩·克尼根算法思路
是否可以像人类直观的计数比特为 1 的位数,跳过两个 1 之间的 0。例如:10001000。
这是布赖恩·克尼根位计数算法的基本思想。该算法使用特定比特位和算术运算移除等于 1 的最右比特位。
当我们在 number 和 number-1 上做 AND 位运算时,原数字 number 的最右边等于 1 的比特会被移除。
基于以上思路,通过 2 次迭代就可以知道 10001000 中 1 的位数。
class Solution:
def hammingDistance(self, x, y):
xor = x ^ y
distance = 0
while xor:
distance += 1
# remove the rightmost bit of '1'
xor = xor & (xor - 1)
return distance
巧妙之处
因为做了减1之后:
- 最右边的1必然必成0
- 最右边的1右边的所有0必然变成1
同时:
- AND操作对左边的数没有影响
- AND操作使得每次抹掉最右边1个0
所以只要结果中不全为0(反过来,即只要还有1存在),就可以一直进行上面的减1和AND操作,每操作1次就代表有一个1,所以就巧妙地求出了1的个数
通过二进制算数的特点来求1个个数,真是太骚了,这得对二进制的理解多么深刻才行。。天才。。