题目链接:https://leetcode.com/problems/number-of-1-bits/
题目内容:
Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also known as the Hamming weight).
For example, the 32-bit integer ’11' has binary representation 00000000000000000000000000001011
, so the function should return 3.
题目分析:
这道题我选择当一回《编程之美》的搬运工,在“求二进制数中1的个数”这一节有详细的说明。
1> 首先是我自己的一种解法,定义一个uint_t的变量作为测试位,初始化为1,即00000000000000000000000000000001,用移位的方式测试给定数的每一位,并加到计数器中。其中要取得给定数n在某一位上的数字,还需要将测试位和n的“与操作”的结果做一个移位,所以的数目为迭代的次数。具体如代码所示
class Solution {
public:
int hammingWeight(uint32_t n) {
int count = 0;
uint32_t test = 1;
for(int i=0;i<32;i++) {
count += (n&test) >> i;
test <<= 1;
}
return count;
}
};
2> 上述运行的结果是8ms,但是其实没什么必要定义一个测试位,只要每次让给定数n右移,并与0x01做“与操作”就能得到每一位上的数字,这就是《编程之美》上面的解法二,测试了下,的确要快了一些,用了4ms,至少在这道题上是这样。
int count = 0;
for (int i = 0; i < 32; i++) {
count += n&0x01;
n >>= 1;
}
return count;
3> 下面祭出编美里的第一种解法,其实也是最容易想到的,编美上第一种解法往往不是最好的,从分析来看的确是这样,通过除法和取余的操作肯定比位运行慢,因为bit才是计算机最喜欢的语言。原理是这样的,每次对n取余,这样的结果肯定就是最后一位的数字,用计数器加起来,这样之后将n除以2,表示往右移了一位。比较打脸的是,该解法的在这道题的运行速度上也是4ms。
int count = 0;
while(n) {
if(n % 2 == 1)
count++;
n /= 2;
}
return count;
4> 按照编美上面的解释,也的确有道理,有些零的位没必要做测试或者累加操作,只计算当前的某一个1就行了,直接贴出解法。
int count = 0;
while(n) {
count++;
n &= (n-1);
}
return count;
又一次打脸的是,这个解法也是用了8ms。。。当然,编美上面还有传统的暴力打表法,向来是oj中最为不耻但是效率最好的,毕竟下标O(1)啊。
补充一下:在这道题中已经指明了是unsigned int,因此是不用考虑负数的。假设输入的参数中规定是整数,即n可能为负数,这时候解法2就失效了,因为对于带符号的整数右移,如果整数n是正数,右移的时候会在最左也就是最高位补0,这没问题;如果n是负数,为了保证右移后还是负数,右移的时候会在最左也就是最高位补1,这样最后整个数变成0XFFFF而导致死循环,因此要根据输入的类型选择算法,按照编美和剑指offer的推荐首选解法4.