题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。
1)可能引起死循环的解法:先判断整数二进制表示中最右边一位是不是1。接着把输入的整数右移一位,此时原来处于从右边数起的第二位被移到最右边了,再判断最右边的数是不是1,用(n&1)判断。这样每一次移动一位,直到整个整数变成0为止。
int NumberOf1(int n)
{
int count = 0;
while(n) {
if(n & 1)
count++;
n = n >> 1; //移位运算比除法的效率要高
}
return count;
}
如果处理的是一个负数,比如0x80000000,把负数0x80000000右移一位的时候,并不是简单地把最高位的1移到第二位变成0x40000000,而是0xC0000000,这是因为移位前是个负数,仍然要保证移位后是个负数,因此移位后的最高位会设置为1。如果一直做右移运算,最终这个数字就会变成0xFFFFFFFF而陷入死循环。
思考:我们就会想,如果输入的数n不移动,那我们就左移1。
解法二:具体思路:首先把n和1做与运算,判断n的最低位是不是1。接着把1左移一位得到2,再和n做与运算,就能判断n的次低位是不是1……,这样反复左移,每次都能判断其中是不是1。这个解法中循环的次数等于整数二进制的位数,32位的整数需要循环32次。
int NumberOf1(int n)
{
int count = 0;
unsigned int flag = 1;
while(flag)
{
if(n & flag)
count ++;
flag = flag << 1;
}
return count;
}
*最好的解法:“整数中有几个1就只需要循环几次。*
具体分析:把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。
int NumberOf1(int n) {
int count =0;
while(n) {
++count;
n = n & (n-1);
}
return count;
}
相关题目:
1)用一条语句判断一个整数是不是2的整数次方。一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,而其他所有位都是0.根据前面的分析,把这个整数减去1之后再和它自己做与运算,这个整数中唯一的1就会变成0。
2)输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。比如10的二进制表示为1010,13的二进制表示为1101,需要改变1010中的3位才能得到1101。我们可以分为两步解决这个问题:第一步求这两个数的异或,第二步统计异步结果中1的位数。