题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如,把9表示成二进制是1001,有2位是1。因此,如果输入9,则该函数输出2。
初步思路: 数字循环和1 进行与运算( & 1),可以判断数字的最后一位是否为1!
发现问题: 负数右移左边补位为1,会多统计。
如果是正数,可以使用上述方法,加快的循环判断条件为数字为0
为了解决上述问题,
使用辅助数字进行判断,只移动辅助数字,辅助数字移动统计数字的位数
如int为32位,辅助数字必须循环判断32位是否含1
实现代码:
#include<iostream>
using namespace std;
int CountOne(int n) {
int count = 0;
int flag = 0b1;
while (flag) {
if (flag & n)
count++;
flag <<= 1;
}
return count;
}
int main()
{
cout << CountOne(5);
}
更快的解法:
先了解一个规律:数字减一后能将其二进制上最后一位1变为0
(C中0b为二进制,0x为十六进制)
比如二进制
0b10001 - 0b1 = 0b10000
0b11000 - 0b1 = 0b10111
并且最后一个1后面的0全部变成1 100…00 -> 011…11
考虑 与运算 性质
每次将减一后的数字与原数字 与运算 便可得到原数字变最后一个1为0的新数字
同样加速了运算
实现代码:
#include<iostream>
using namespace std;
int CountOne(int n) {
int count = 0;
while (n) {
count++;
n &= n - 1;
}
return count;
}
int main()
{
cout << CountOne(10);
}
- 拓展思考1:
新方法能够每次把数字最右边的1变为0。
可以用来判断一个数字是否是2的整数次方,如果是,二进制1的个数必为1
一行代码判断:
return !(n & (n - 1));
- 拓展思考2:
数字一到数字二的数字变化数问题。
如0111 到 1000 需要变化4个bit位
①找到两者数字差别 -> 异或运算 (相当于标记两数不同的位为1)
②重复上述方法便可得到1的数量