面试题:统计给定位串中1的个数

种群计数就是统计一个位串中1的个数。JavaShort,IntegerLong都有bitCount方法,就是种群计数的实现。这类问题不仅很基础,也很重要。如果将其作为面试题,很容易考察算法能力的高低。

  1. 最简单的实现

最容易想到的方法就是遍历每一位,测试该位是否是1。代码如下:

intcount = 0;

for(inti = 0; i < Integer.SIZE; i++) {

if((a & (1 << i)) != 0) {

count++;

}

}

returncount;

假设位串的长度为n,则算法的时间复杂度为O(n)。对于统计整形这样的,因为其位数最多为64位,所以基本上可以算是常数。但如果要统计很多个整形,那么其实现将具有一个很大的常数。

  1. 一种改进

这种改进是基于这样一个事实:操作x^(x-1)能把最低1位置0。这样通过不断将最低1为置0,直到x等于0为止。具体实现如下:

intcount = 0;

inta = x;

while(a != 0) {

a^= a – 1;

count++;

}

改进之后,性能有很大提升。理论上,所有位都为1的情况很少,而位串中1的个数期望位位串长度的一半。所以其平均时间复杂度为第一种方法的一般。

  1. 查表法

考虑到给定位数(比如4位)中1的个数是可以预先给定了。一个整型有32位,只要查8次表就好了。代码如下:

Int[]table = new int[]{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};

intcount = table[a&0x0f] + table[a&0xf0] + table[a&0xf00]+ table[a&0xf000] + table[a&0xf0000] + table[a&0xf00000]+ table[a&0xf000000] + + table[a&0xf0000000];

上面编译后得到的汇编指令很短,性能非常高,是常数级别的。

  1. 分而治之

统计32位的1个数,可以分解成两个16位的统计。这个方法在串行的机子上并没有实现性能上的提升。但如果并行计算,性能则能提升一倍。特别适合现在主流的多核计算机。具体的实现如下:

x= x & 0x55555555 + (x >> 1) & 0x55555555; //计算每21的个数

x= x & 0x33333333 + (x >> 2) & 0x33333333; //计算每4

x= x & 0x0F0F0F0F + (x >> 4) & 0x0F0F0F0F; // 计算每8

x= x & 0x00FF00FF + (x >> 8) & 0x00FF00FF; // 计算每16

x= x & 0x0000FFFF + (x >> 16) & 0x0000FFFF;// 计算每32

上面的实现,没有用到分支指令和内存引用,单纯的位操作,加法和赋值操作,因此性能应该是最高效的了。这也是JavaInteger类型的bitCount函数的实现。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值