剑指offer-10:二进制中1的个数

来源:互联网 发布:温度数据采集板 编辑:程序博客网 时间:2024/04/25 16:13

左移、右移运算符

// 把m左移n位。最高位丢弃,最右边补0m << n/* * 把m右移n位。最右边丢弃,最左边分情况 * 无符号数:用0填补最左边 * 有符号数:符号位填充最左边 */m >> n

实现一个函数,输入一个整数,输出该整数二进制表示中1的个数。如9二进制为1001,输出2。

思路:

对于一个int型整数,系统以32位表示。我们可以设置一个无符号型数1,不断左移1和该数与,从0-31位逐个做与运算,逢1个数加1。

第01次:00000000000000000000000000000001
第02次:00000000000000000000000000000010

第32次:10000000000000000000000000000000
第33次:00000000000000000000000000000000

代码实现:

int NumberOf1_1(int n){    int count = 0;    unsigned int flag = 1;    while(flag)    {        if(n & flag)            count++;        flag = flag << 1    }    return count;}

不论该数是正整数还是负整数,flag不管每次都移位32次。

不要移动原数和1与。若是负数,则最左边添加1,最终会把该数搞成0xFFFFFFFF,每位都是1,陷入死循环。


牛逼解法:这种不是人人想得到,除非把计算机系统与结构那本书了如指掌,对底层运算有深刻理解。否则只能看了才知。

发现:把一个整数减去1,再和原整数做与运算,会把该整数最右边的一个1变为0。

如:
5 = 101,4 = 100,5 & 4 = 100(新数)
100 - 1 = 011,100 & 011 = 000(循环终止)

代码实现:

int NumberOf1_2(int n){    int count = 0;    // 不为0时,肯定有1    while(n)    {        count ++;  // 计数+1        n = (n-1) & n; // 消去1,再看    }    return count;}

细想:一个整数减去1,则会把从最右边的1起始的位全部取反。

原数1000001001000 1 0 0减去11000001001000 0 1 1相与:1000001001000 0 0 0

两者相与则把从最右边1起始的位全部置0了。就消去了最右边的1,周而复始,直到消完。


相关题目:

1.用一条语句判断一个整数是不是2的整数次方。

答:一个数若是2的整数次方,则其只有一位是1,其余为0。将此数和(此数-1)做与运算,若结果为0,则是的。否则不是。

2.输入两个整数,计算需要改变第一个数的多少个二进制位才能得到第2个数。

答:实际上问两个数有多少位不同?

分两步考虑:首先将两个数做异或运算,得到的数,不一致的位为1。然后统计其中为1的位的个数即可(本题解法)。

int i = 128;int j = 127;int k;k = i ^ j; // 异或运算cout << NumberOf1_2(k) << endl; // 8// & 与运算  | 或运算 
原创粉丝点击