牛客剑指OFFER JZ11 二进制中1的个数

题目描述
输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

思路一:
1、对于任意一个32位二进制表示的数n,现取n = xxxxxx01100 为例子,显然 n-1 = xxxxxx01011,则 n&(n-1) = xxxxxx01000;
2、上述例子想说的是,n&(n-1) 这一式子得到的是 n 的最低位的 1 变为 0 后的值。
3、令 n 为循环进行条件, n = n&(n-1),当循环结束时,循环进行的次数就是 1 的总数。

     int  NumberOf1(int n) {
        int cnt = 0;
        while(n) {
            cnt++;
            n = n & (n - 1);
        }
        return cnt;
     }

思路二: 这是在一道题目中看到做法。
1、对于某个二进制数,如 n = 1011,取 n = n&(0x5) +((n>>1) & 0x5) = 0001 + 0101 = 0110;
(1)这个算式的意义是将n的相邻的两位相加,得到的结果也以二进制形式记录下来。
(2)由于二进制不是0就是1,所以得到的结果中,每相邻的两位组成的数值都代表着原先的n在这个位置上1的数量。
(3)例如上式的结果 0110,代表 n 的第1和第2位上( 11 部分)1的数量为 10 = 2;第3和第4位上( 10 部分)1的数量为 01 = 1。
(4)最好自己算一算,看看结果是怎么来的。
2、对于上式结果 n = 0110,取 n = n&(0x3) +((n>>2) & 0x3) = 0010 + 0001 = 0011;
(1)这个算式的意义是将n的相邻的两位一组,然后相邻的两组相加,得到的结果也以二进制形式记录下来
(2)由于 0110 中每相邻的两位组成的数值都代表着原先的n在这个位置上1的数量,所以得到的结果中,每相邻的四位组成的数值都代表着原先的n在这个位置上1的数量。
(3)例如上式的结果 0011,代表 n 的第1、第2、第3和第4位上( 整个 1011) 1的数量为 0011 = 3。

由于 1011 本身也只有四位,所以到这里就算好了,但对于 32 位的数还需要 相邻的四位一组,然后相邻的两组相加、八位、直到十六位

代码中的 int n = n1 & 0x7fffffff;主要是针对负数,将符号位的 1 改为 0 ,最后输出时还要+1。
但在编译器上跑,不用这一段也能出正确结果,也就是说不用考虑负数,但牛客上面会出错…原因不明。

     int  NumberOf1(int n1) {
         int n = n1 & 0x7fffffff;
         n = (n & 0x55555555) + ((n>>1) & 0x55555555);
         n = (n & 0x33333333) + ((n>>2) & 0x33333333);
         n = (n & 0x0f0f0f0f) + ((n>>4) & 0x0f0f0f0f);
         n = (n & 0x00ff00ff) + ((n>>8) & 0x00ff00ff);
         n = (n & 0x0000ffff) + ((n>>16) & 0x0000ffff);
         if(n1 < 0)
             return n+1;
         else
             return n;
     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值