题目:
输入一个整数n,输出这个整数二进制下1的个数。
读入样例:
13
输出:
3
解释:
13二进制下是1101,一共3个1。
看到这道题,首先应考虑到:
n是一个整数,而不是正整数,因此,读入一个数字进来以后,第一件事就是应该将它变成它的绝对值。
之后来考虑如何把它二进制下1的个数求出来。
思路1:
短除法。来看这样一个例子:
在思路1的基础上,n%2实际上就是看n的二进制下第一位是不是1,那么让n和0000001这个二进制数做一次与运算一样可以得到。
计算机中,位运算的速度要快于四则运算,因此,可以把n%2改成n&1。
同样的道理,n/=2可以改成n>>1。
对于这个题目,我们只关心它二进制是1的位置,但使用短除法,依旧没有脱离枚举算法,不是很高效,有没有更快的办法可以不枚举就找到它二进制下每一个为1的位呢?
看这样一个例子:
13=1101,13-1=12=1100,13&12=1100=12,相当于把第一个1消除掉了
12=1100,12-1=11=1011,12&11=1000=8,相当于把的第二个1消除掉了
8=1000,8-1=7=0111,8&7=0000=0,相当于把8的第三个1消除掉了
一共只进行了3次这样的操作,就把n二进制下所有的1都找了出来。
这样做的原因在于,给一个数字减1,就相当于把它从右向左第一个是1的位变成了0。这个位置左边的数都没有改变,右边的全部变成了1。
此时,把它和本来的那个数进行与操作,因为本来的数字这一位右边全是0,因此,这一位右边与操作以后,一定全是0,而这一位一个是1,一个是0,必然是0,而这一位的左边,本来是多少就还是多少。相当于把这个数字二进制下最右边的1给消除掉了。
输入一个整数n,输出这个整数二进制下1的个数。
读入样例:
13
输出:
3
解释:
13二进制下是1101,一共3个1。
看到这道题,首先应考虑到:
n是一个整数,而不是正整数,因此,读入一个数字进来以后,第一件事就是应该将它变成它的绝对值。
之后来考虑如何把它二进制下1的个数求出来。
思路1:
短除法。来看这样一个例子:
13/2=6……1 6 /2=3……0 3 /2=1……1 1 /2=1……1 倒着数上来,就是1101,也就是13二进制下的每一位。
while (n!=0)
{
sum+=n%2;
n/=2;
}
思路2:
在思路1的基础上,n%2实际上就是看n的二进制下第一位是不是1,那么让n和0000001这个二进制数做一次与运算一样可以得到。
计算机中,位运算的速度要快于四则运算,因此,可以把n%2改成n&1。
同样的道理,n/=2可以改成n>>1。
while (n!=0)
{
sum+=n&1;
n>>1;
}
思路3:
对于这个题目,我们只关心它二进制是1的位置,但使用短除法,依旧没有脱离枚举算法,不是很高效,有没有更快的办法可以不枚举就找到它二进制下每一个为1的位呢?
看这样一个例子:
13=1101,13-1=12=1100,13&12=1100=12,相当于把第一个1消除掉了
12=1100,12-1=11=1011,12&11=1000=8,相当于把的第二个1消除掉了
8=1000,8-1=7=0111,8&7=0000=0,相当于把8的第三个1消除掉了
一共只进行了3次这样的操作,就把n二进制下所有的1都找了出来。
这样做的原因在于,给一个数字减1,就相当于把它从右向左第一个是1的位变成了0。这个位置左边的数都没有改变,右边的全部变成了1。
此时,把它和本来的那个数进行与操作,因为本来的数字这一位右边全是0,因此,这一位右边与操作以后,一定全是0,而这一位一个是1,一个是0,必然是0,而这一位的左边,本来是多少就还是多少。相当于把这个数字二进制下最右边的1给消除掉了。
while (n!=0)
{
sum++;
n = (n-1)&n;
}