题目描述

输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示
示例:
输入:10
返回:2

我们发现将10 转成二进制为1010,按照题目的描述,表示1的个数有2个,所以返回2

这时我们自定义输入个数:15,看看二进制结果是多少?

返回1的个数的结果应该是4,为什么输入10 的二进制是1010,输入15是1111?

二进制转换

我们使用Byte字符的二进制做演示,首先我们直观一点举例正数说明
图片说明
图片说明
以此类推....那么十进制转二进制该怎么做呢?来看看规律?
图片说明
有没有发现?从右开始往左是2^0(二的零次方)、2^1(二的一次方)、2^2(二的平方)、2^3(二的三次方)
图片说明
根据前面知识点,你知道:01101110的十进制是多少么?
图片说明
那么我们说Byte表示 -128 ~127 ,那么0和1 是怎么表示正数和负数的呢?
图片说明
我们现在知道二进制的最高位:0 正数 1 负数
那么对于整数还要提三个码:原码、反码、补码
图片说明
那么我们思考一下:在计算机中: -14 是什么样的呢?

接下来看看负数的解析图:十进制:14、二进制:00001110
图片说明
接下来我相信大家都了解了什么是原码、反码、补码了,而题目中刚提到负数用补码来展示

在Java中整数常量默认为int类型,而用二进制定义整数的时候默认为32位

解法一:

我们先从32位的思路开始一个一个开始比较,需要比较32次

 public class Solution {
    public int NumberOf1(int n) {
      int result =0;
        //我们可以直接利用移位操作对一个十进制数进行移位操作,
        // 即:将最高位的数移至最低位(移31位),除过最低位其余位置清零,使用& 操作,可以使用和1相与(&),
        // 由于1在内存中除过最低位是1,其余31位都是零,然后把这个数按十进制输出,如果为1,则记为1,从0累加
        // 再移次高位,做相同的操作,直到最后一位 
      for(int i = 31;i >= 0; i--) {
            if((n >>> i & 1)==1){
                result++;
            }
       }
        return result;
    }
}

时间复杂度:O(32)
空间复杂度:O(1)

会不会有小伙伴遇到& 什么意思?其实是将两边的数转换为二进制位,然后运算最终值

简单来说就是
1&1=1 1&0=0
0&0=0 0&1=0

那么n >>>1 是什么意思呢? >>>其实是右移运算符

当我们遇到没有符号的右移运算符时,比如说15的二进制位是0000 1111 , 右移1位就是0000 0111

若我们把0000 0111 转为十进制就是7

若我们按照思路一个一个比较,那么输入10,他的十进制就是0000 1010

我们移动i个就可以丢弃,所以 n>>> i 即丢弃,高位补位的意思

题目的要求是表示1的个数,此时我们只需要res == 1 即满足要求

解法二:

上一种解法中,我们发现无用操作是若当前位是0, 还是会做判断,然后一位一位的移动
那么能不能让遇到0直接略过?什么意思呢?

如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,如果最右边的1后面还有0的话,那么在1后面的所有的0都会变成1,其余所有位将不会受到影响

我们举个示例看看,比如说10 和9

我们输入十进制:10 ,转换的二进制是1010,当我们将10减1时,就会变成9
我们输入十进制:9 ,转换的二进制是1001,这时(1010)从右往左数最右边1就会变为0

原最右边的1后面还有个0,所以0变成1,那么就是1010 -> 1001

这个时候如果我们再把原来的整数和减去1之后的结果做位运算

从原来整数最右边一个1那一位开始所有位都会变成0

如1100 & 1011 = 1000 也就是说,把一个整数减去1,再和原整数做运算,会把该整数最右边一个1变成0 那么一个整数的二进制有多少个1,就可以进行多少次这样的操作

    public int NumberOf1(int n) {
        //解法 把一个整数n减去1,再和原来的整数与运算,会把该整数的最右边的1变成0,
        //那么,一个整数的二进制中有多少个1,就可以进行多少次这样的操作。循环结束的条件是n为0
        int result=0;
        while(n!=0){
            n = (n-1) & n;
            result++;
        }
        return result;
    }

时间复杂度:O(n) n为输入参数n中1的个数
空间复杂度:O(1)