问题描述:对于1个字节(8bit)的无符号整形变量,求其二进制表示中1的个数,要求算法的执行效率尽可能的高。
例子:输入7,二进制表示为:0000 0111,则二进制表示中1的个数为3
解法一:
举一个8位的二进制例子。对于二进制操作,除以一个2原来的数字将会减少1个0,如果除的过程中有余,就表示当前位置上有1。
例如:10100010
第一次除以2,商101001,余数0
第二次数以2,商101000,余数1
所以可以考虑用整形数据除法的特点,通过相除和判断余数的值来分析。
下面是参考代码:
int Count(unsigned char u){
int number=0;
while(u){
if(u%2==1)
number++;
v/=2;
}
return number;
}
其实通过移位操作同样可以解决问题,不过问题的关键是如何判断是否有1存在,我们可以用“&”运算符来判断,如果结果为1,就代表最后一位为1,否则则为0。
下面是参考代码:
int Count(unsigned char u){
int number=0;
while(u){
number+=v & 0x01;
v>>=1;
}
return number;
}
位操作虽然比除,余操作效率高了不少。不过在这两种情况下时间复杂度仍然为:O(Log2u),其中Log2u为二进制的位数。如果可以让时间复杂度只与二进制表示中“1”的个数有关,那么时间复杂度为进一步降低。
如果数字u不为0,则u的二进制表示中必然至少有1个1,如果我们可以每次减少其二进制表示中的1个“1”,那么时间复杂度就降低到了至于“1”的个数有关了。参考代码如下:
int Count(unsigned char u){
int number=0;
while(u){
u&=(u-1);
number++;
}
return number;
}
现在时间复杂度已经降低到了O(M),其中M是1个个数。看似已经很不错了,不过还有一种更简单粗暴的方式,时间复杂度可以做到O(1),是典型的以空间换时间。下面是参考代码:
int CountTable[256]={
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,
3,4,4,5,1,2,2,3,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5
,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,
4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4
,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,
2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5
,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,
5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4
,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
};
int Count(unsigned char u){
return CountTable[u];
}