熟悉的有三种解法:
1.程序内置的方法:
一般我们的语言这种基本的函数都是有的,比如:
-
golang: bits.OnesCount
-
C/C++: __builtin_popcount
-
Java: Integer.bitCount
复杂度分析
- 时间复杂度:O(1) 不同语言的实现方法不一,我们可以近似认为其时间复杂度为 O(1)O(1)。
- 空间复杂度:O(1)
2. 最基本的轮询方法
// s 为我们的目标数字
for s > 0 {
// 位移后和1与运算,如果为1那最低一位就是1
ans += s & 1
// 向右移一位,最低位舍弃
s >>= 1
}
复杂度分析
-
时间复杂度:O(log C),其中 C 是元素的数据范围。
-
空间复杂度:O(1)
3.Brian Kernighan 算法
在方法二中,对于 s=10001100 的情况,我们需要循环右移 8 次才能得到答案。而实际上如果我们可以跳过两个 1 之间的 0,直接对 1 进行计数,那么就只需要循环 3 次即可。
我们可以使用Brian Kernighan 算法进行优化,具体地,该算法可以被描述为这样一个结论:记 f(x) 表示 x 和 x−1 进行与运算所得的结果那么 f(x) 恰为 x 删去其二进制表示中最右侧的 1 的结果。
Go代码实现:
for s > 0 {
// 累加的技术
ans++
// 算法核心
s &= s - 1
}
复杂度分析
- 时间复杂度:O(1),在 Java 中 Integer 的大小是固定的,处理时间也是固定的。 但是该方法需要的迭代操作更少。
- 空间复杂度:O(1),使用恒定大小的空间。
来源
汉明距离 | 力扣(LeetCode) [汉明距离 | 题解(LeetCode)](