考查位运行。这已经是一个非常常见的题目了,我这里主要也是收集了多种解法。自己拿定,面试官最想看到的吧。
(1)懂C的都能写出来的方式 ,这个时间复杂度花在循环上,由位数决定
int countBit(unsigned int n)
{
int count = 0;
while(n)
{
if(n&0x1)
count++;
n>>=1;
}
return count;
}
(2)更优秀一点的,我比较喜欢的。这个时间复杂度就有了优化,与n中一的位数有关。关键技巧点在n&=(n-1). 假如随便看几位n=000101,n-1=000100. n&(n-1)=000100.所以可以看出,每次都是去掉了n中的低位的一个1.
int countBit(unsigned int n)
{
int count=0;
while(n)
{
n&=(n-1);
count++;
}
}
(3)有没有常数时间呢,当然是有的,最简单的就是想到用空间换时间。在《编程之美》里面有讲到这一方法,那是计算一个无符号8位的的值,建一个table[256],用n来做索引。这个方法 我不喜欢,想到这里,我们32位,就很难实现了,空间代价太大了。换另一种实现方式(4)吧
(4)这里就是数学的技巧和位运算的技巧了。
int countBit(unsigned int n)
{
int tmp = n;
tmp = tmp - (tmp>>1) & 033333333333
- (tmp>>2) & 011111111111;
return ((tmp+tmp>>3) & 030707070707 )% 63;
}
我觉得第(2)(4)应该会给考官好的印像。
扩展 :给定两个正整数A和B,请问至少要改变多少位,才能使A变成B。
int tmp=A^B;
countBit(tmp);
就是想要的结果。该拓展也是来自《编程之美》的问题。