剑指offer11_二进制中1的个数

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

首先,复习下java的int型表示范围:

java的int型由4个字节组成,即32位。 减去最高位符号位,共有31位,故表示的范围是 正负2^32(10位十进制数)。

再“预习”下负数的补码表示方法。

(1),java使用2的补码这种方式来编码负数。即,除过符号位,先对每一位取反,再加1; 
例如: -42就是通过取反42中所有的位00101010来表示,得到11010101,然后再加1,得到11010110,即-42 。要解码一个负数,首先取反其所有的位,然后加1。例如-42,或11010110取反后为00101001,或41,然后加1,这样就得到了42。

(2),其次,比较特殊的几个数字:+0, -0, -1; 
假定有一个byte型值,0用00000000代表。在补码表示中,只是取反所有的位,即生成11111111,它代表负0。而在整数数学中,负0是无效的。所以可以使用2的补码来表示负数。当使用2的补码时,对补码加1,产生了100000000。但这时1位太靠左不能返回到byte类型的值。因此我们规定,-0和0的表示方法是一样的,-1的解码为11111111。

正数的补码 = 原码

负数的补码 = {原码符号位不变} + {数值位按位取反后+1} 

                     = {原码符号位不变} + {数值位从右边数第一个1及其右边的0保持不变,左边安位取反}

---------------------

思路:看到二进制字眼,一般都是考察的位运算。

要明确的一件事是,负数存储的时候本身就是补码,所以不需要自己计算原码和补码,直接十进制计算即可。

思路1:将n和1与(&)运算,然后再右移;其中,如果运算结果是1则表明n的最后一位是1,count+1;否则就是最后一位是0,count不变.(很常见的错误思路,与除以2取余的思路是一样的,都是没法直接处理负数)

缺陷:这种没有考虑到n是负数的时候。在计算机中负数存储成补码,右移的时候补位是1而不是0,所以1会一直存在,这样会造成一直循环,导致陷入死循环。

思路2: 整数n每次无符号右移一位,检查最右边的bit是否为1来进行统计;代码如下:

public int count1(int n){
    int res = 0;
    while(n != 0){
        res += n&1;//用n&1获取二进制最低位,不管是0还是1都可以直接加上,不用再if判断count计数了
        n>>>=1; //n>>>=1;是无符号右移一位,等效于:n=n+1;
    }
    return res;
}

思路3:一个整数减去1,相当于把这个数最右边的1的后边的变成0,0变成1;1的前边的0,1不变。

举例说明:1100,减去1,变成1011。可以看出把1100最右边的1变成了0。

所以我们可以用n&(n-1)来计算有多少个1;n能运行多少次这样的操作,就有多少个1.

public class Solution {
    public int NumberOf1(int n) {
        int count=0;
        while(n!=0){
            count++;
            n=n&(n-1);
        }
        return count;
    }
}
--------------------- 
参考的博客原文:https://blog.csdn.net/yingzizizizizizzz/article/details/70162721 

猜你喜欢

转载自blog.csdn.net/lilililililydia/article/details/87881688