剑指 Offer(第2版)面试题 15:二进制中1的个数
- [剑指 Offer(第2版)面试题 15:二进制中1的个数](#剑指 Offer(第2版)面试题 15:二进制中1的个数)
剑指 Offer(第2版)面试题 15:二进制中1的个数
题目来源:26. 二进制中1的个数
此题与 Leetcode191. 位1的个数 一致。
解法1:位运算
循环检查给定整数 n 的二进制位的每一位是否为 1。
当检查第 i 位时,我们可以让 n 与 2^i^ 进行与(&)运算,当且仅当 n 的第 i 位为 1 时,运算结果不为 0。
设置一个计数器,遍历一次即可得到位 1 的个数。
注意:1 << i 必须是 uint32_t 的。
代码:
c
class Solution
{
public:
int NumberOf1(int n)
{
int count = 0;
for (int i = 0; i < 32; i++)
if (n & (uint32_t)1 << i)
count++;
return count;
}
};
复杂度分析:
时间复杂度:O(k),其中 k = 32,是 int 的位数。
空间复杂度:O(1)。
解法2:n & (n - 1)
随便一个 n:
那么 n - 1 会发生什么:对于上面随便给的一个 n,减去 1,但是低 2 位都是 0,减 1 必然需要借位,那何时结束呢?答案就是遇到 1 的时候。如果第一步骤中给的 n 末尾为 1,那么就直接在低位就结束了,也符合遇到 1 就停止的规则。
总结而言,n - 1 操作:
-
无论是借位,还是减 1,遇到 1 就停止;
-
从低位到高位,一直到 1,每一位都发生了反转。
n & (n - 1):将 n 最低位的一个 1 变成 0。
于是,要求一个数 n 中二进制 1 的个数,我们可以不断地对 n 进行 n = n & (n - 1) 操作,每进行一次,n 中最低位的 1 就会变成 0,直到 n 变成 0 为止,操作次数就是 n 中二进制 1 的个数。
代码:
c
class Solution
{
public:
int NumberOf1(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
};
复杂度分析:
时间复杂度:O(log n)。
空间复杂度:O(1)。