常规解法
为避免死循环(负数右移补1),我们选择左移1来判断
1 int NumberOf1(int n){ 2 int count = 0; 3 unsigned int flag = 1; 4 while(flag){ 5 if(n & flag){ 6 count++; 7 } 8 flag = flag<<1; 9 } 10 return count; 11 }
在这个解法中,循环的次数等于整数二进制的位数,32位的整数需要循环32次。
例如:
int i = 0x40000000; //2进制的01000000...0000
i = i << 1;
那么,i在左移1位之后就会变成0x80000000,也就是2进制的100000...0000,符号位被置1,其他位全是0,变成了int类型所能表示的最小值,32位的int这个值是-2147483648,溢出.如果再接着把i左移1位会出现什么情况呢?在C语言中采用了丢弃最高位的处理方法,丢弃了1之后,i的值变成了0.
左移里一个比较特殊的情况是当左移的位数超过该数值类型的最大位数时,编译器会用左移的位数去模类型的最大位数,然后按余数进行移位,如:
int i = 1, j = 0x80000000; //设int为32位
i = i << 33; // 33 % 32 = 1 左移1位,i变成2
j = j << 33; // 33 % 32 = 1 左移1位,j变成0,最高位被丢弃
O(1)的解法
思路:把一个整数减去1,再和原整数做与运算,会把该整数最右边的1变成0.那么一个整数的二进制表示中有多少个1,就进行多少次这样的操作。
1 int NumberOf1(int n){ 2 int count = 0; 3 while(n){ 4 ++count; 5 n = (n-1) & n; 6 } 7 return count; 8 }