问题描述
任意给定一个 32 位无符号的整数 n,计算 n 的二进制表示中 1 的个数,比如 n = 3(011))时,返回 2
这是一到笔试面试经典的题目,下面介绍几种解法来实现这一道题目,如果你有更好的解法,欢迎指导交流
方法一:普通法
通过移位解决,每次向右移一位( >> 1),然后判断最后一位是不是 1(&1),最多循环 32 次
int BitCount(unsigned int n)
{
int count = 0;
while (n > 0) {
if (n & 1 == 1) {
count++;
}
n = n >> 1;
}
return count;
}
使用下面的测试用例计算一下时间
int main(void) {
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
for (uint32_t i = 1; i <= numeric_limits<long long>::max(); ++i) {
BitCount(i);
}
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> time_span = end - start;
std::cout << "time:" << time_span.count() << std::endl;
getchar();
return 0;
}
时间打印是:time:0.0012
方法二:快速法
这种方法速度比较快,运算次数与 n 中 1 的个数有关,每次不断的清除 n 二进制中最右边的 1,同时累加计数器,一直到 n 为 0,一般笔试面试给出这种解法也就可以了
int BitCount(unsigned int n)
{
int count = 0;
while (n > 0) {
n &= (n - 1);
count++;
}
return count;
}
时间打印是:time:0.0005
最常见的就是这两种办法了,尤其是第二种在面试的时候是很喜欢问的
方法三:查表法
可以看一下 leetcode 这一道题目:https://leetcode-cn.com/problems/counting-bits/,用于求一个连续集合内,所有数字二进制种 1 的个数
要求实现 vector<int> countBits(int num) 函数
这里运用一个比较巧妙的思想,对于一个正整数 n
1、如果 n 是偶数,那么 n 二进制的个数与 n / 2 中二进制的格式都是一样的,比如 2,4,8,16,32,64,他们都只有一个 1,再比如 6 和 3 的二进制都是 2 个 1,因为 n 是由 n/2 左移一位过来的,左移是在结尾补 0,所以 1 的个数并不会增加
2、如果 n 是奇数,那么 n 的二进制个数是 n / 2 中二进制个数 +1,因为 n 是奇数时,相当于 n / 2 左移再加 1
基于上面的思路,我们实现以下 vector<int> countBits(int num) 函数
vector<int> countBits(int num) {
int bits[4] = { 0,1,1,2 };
std::vector<int> result;
result.push_back(0);
for (int i = 1; i <= num; ++i) {
if (i == 4) {
break;
}
result.push_back(bits[i]);
}
if (result.size() == num + 1) {
return result;
}
for (int i = 4; i <= num; ++i) {
int count = result[(i >> 1)];
if (i & 1 != 0) {
count += 1;
}
result.push_back(count);
}
return result;
}
利用了空间来换取时间
参考文章:
其它解法可以参考下面这一篇文章,写的真的挺不错的
https://www.cnblogs.com/graphics/archive/2010/06/21/1752421.html