算法-LeetCode-整数的二进制表示中1的个数

题目

输入一个,输出该数二进制表示中1的个数。 其中负数用补码表示。
说明:对于负数的二进制码,比如-1(由于java中int 为4个直接,总共32位,这里方便表示只取8位)
原码:-1=1000 0001 (最高位为符号位,负数用1表示)
反码:-1=1111 1110 (除了最高位的符号位,其余的全部取反)
补码:-1=1111 1111 (把反码加一,则为补码)
实际上,对于负数,他的二进制表示为补码。所以java中int类型-1,它的二进制全部是1,也就是32位1

解法一:使用与运算符,先看代码

 public int NumberOf2(int n) {
     int count = 0;
     while(n != 0){
         count++;
         n = n & (n-1);
     }
     return count;
 }

这个有点不好理解,举个例子,n为负3。
*原码:-3=1000 0011
*反码:-3=1111 1100
*补码:-3=1111 1101

所以-3的二进制为111111101,而-3-1=-4,
*原码:-4=1000 0100
*反码:-4=1111 1011
*补码:-4=1111 1100

1000 0101
1111 1011
所以-3&-4(1111 1101 & 1111 1100)结果的二进制为1111 1100 = -4
同理-4&-5(1111 1100 & 1111 1011)结果的二进制为1111 1000 = -8
同理-8&-9(1111 1000 & 1111 0111)结果的二进制为1111 0000 = -16
同理-16&–17(1111 0000 & 1110 1111)结果的二进制为1111 0000 = -16
直到最后(1100 0000 & 1011 1111)结果的二进制为 1000 0000 即为-0=0

所以这个比较巧妙的是 n&n-1这个问题,不怎么好理解。

解法二:使用移位,看代码

public int NumberOf1(int n) {
    if(n == 0) return 0;
    int count = 0;

    /**当n为负数,去除最高位的符号位(即-1),将n变为正数*/
    if(n < 0){
        count++;
        //先左移一位,将符号位的1挤掉,再无符号右移一位,高位补0,即为正数
        n = (n<<1) >>> 1;
    }
    do{
        //n和1做与运算,即求最低位是否为1
        if((n&1) == 1) count ++ ;
        //然后n右移,挤掉最低位
    }while((n = n>>>1) > 0);
    return count;
}

这个思路比较好理解,不过要清楚java中的普通右移为>>,而无符号右移为>>>。普通右移符号位是不跟着移动的。

猜你喜欢

转载自blog.csdn.net/u014801432/article/details/81286735