算法原理和步骤如下:
-
原理:
- 该算法的核心思想是利用了一个性质:对于任意一个整数
x
,表达式x & (x - 1)
的结果会将x
的二进制表示中最右边的 1 变为 0。 - 通过不断执行
x = x & (x - 1)
这一操作,直到x
变为 0,就能统计出x
的二进制表示中包含的 1 的个数。
- 该算法的核心思想是利用了一个性质:对于任意一个整数
-
步骤:
- 初始化一个计数器
res
,初始值为 0。 - 对于输入的每个整数
x
,重复以下步骤直到x
变为 0:- 将
x
减去x
的最低位的 1,即x = x & (x - 1)
。 - 每减去一次最低位的 1,计数器
res
加 1。
- 将
- 返回计数器
res
的值,即为x
的二进制表示中包含的 1 的个数。
- 初始化一个计数器
该算法的时间复杂度与整数 x
的二进制表示中 1 的个数成正比,具有较高的效率。
问题:
请计算给定数列中每个数字的二进制表示中包含的1的个数。
模板:
求n的第k位数字: n >> k & 1 返回n的最后一位1:lowbit(n) = n & -n
例:
x = 00001010101000 lowbit(x)得到的是1000
-x = ~x + 1 负数表示为补码 ,补码等于反码加1
因为 2 + (- 2) = 0
2为0010 - 2 = ~2 + 1 = 1110 0010 +1110 = 10000 = 0000
代码:
#include<iostream>
using namespace std;
// lowbit 函数返回一个整数的二进制表示中最低位的 1 所代表的数值
int lowbit(int x)
{
return x & (-x);
}
int main()
{
int n;
cin >> n; // 输入整数 n,表示接下来会输入 n 个整数
for (int i = 1; i <= n; i++)
{
int x, res = 0;
cin >> x; // 输入一个整数 x
// 计算 x 的二进制表示中包含的 1 的个数
while (x)
{
x -= lowbit(x); // 不断减去 x 的 lowbit
res++; // 每减去一次 lowbit,res 自增 1,统计 1 的个数
}
cout << res << " "; // 输出 x 的二进制表示中包含的 1 的个数
}
return 0;
}
总结:
计算一个整数的二进制表示中包含的1的个数是一项常见的任务。这个任务的解决方法有多种,其中包括布赖恩·克尼根算法和位运算技巧。布赖恩·克尼根算法利用了一个性质:对于任意一个整数 x,x & (x - 1) 的结果会将 x 的二进制表示中最右边的1变为0。通过重复这个操作,直到 x 变为0,就能统计出 x 的二进制表示中包含的1的个数。另一方面,利用位运算技巧,例如 x & (-x) 可以得到 x 的二进制表示中最低位的1所代表的数值,进而可以用来统计1的个数。选择适合问题需求和编程环境的方法,可以更高效地完成二进制中1的个数的计算任务。