zoukankan      html  css  js  c++  java
  • 【剑指Offer】二进制中1的个数

    题目描述

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

    补码

    解题前,我们先来了解一下补码。在计算机系统中,数值都是用补码来表示和存储的。
    而原码就是数值的二进制数表示,最高位1表示负数。
    以32位数值举例
    1的原码就是

    -1的原码就是

    正数的补码等于原码
    负数的补码等于其原码按位取反后(除了最高位)加1,比如-1的补码就是32个1

    使用补码的好处在于,可以将符号位和数值位统一处理,加法与减法也可以统一处理。
    比如3 - 1,等价于3 + (-1),则对于计算机来说将3和-1的补码直接相加就可以,计算过程如下图所示。如果直接使用数值的原码表示,则不会得到正确的结果,感兴趣的同学可以计算试一下,这里不再赘述。

    解法1

    对于本题,首先想到的是将二进制数一直右移,这样的话该数的每一位都会依次成为最低位,然后将该数和1相与,计算1的个数。(由于1只有最低位是1,其他位都是0,某个数和它相与后,结果如果是1,就说明该数最低位是1,否则就是0)
    按照以上思想,实现的代码如下,但是请注意,这样的写法是错误。没有考虑负数的情况,和正数右移最高位补0不同的是,负数右移最高位补1,这样就会有无数个1,导致死循环。

    public int NumberOf1(int n)
    {
        int count = 0;
        // 没有考虑负数,一直不会等于0
        while(n != 0)
        {
            if ((n & 1) == 1)
                count++;
            // 负数右移最高位补1
            n >>= 1;
        }
        return count;
    }
    

    既然将目标数右移和1与行不通,那么我们可以反过来,将1不断左移(从最低位到最高位每一位依次是1,其他位是0),然后和目标数相与来求1的个数。具体过程如下图所示

    实现代码

    public int NumberOf1(int n)
    {
        int unit = 1, count = 0;
        while (unit != 0)
        {
            if ((unit & n) != 0)
                count++;
            unit <<= 1;
        }
        return count;
    }
    

    解法2

    上面解法1的时间复杂度是O(n的位数),n有所少位就要循环多少次。可以利用一个小技巧,降低算法的时间复杂度。
    先来看一个例子,对于任意一个数将其减1,比如7
    7的补码表示是

    (7的补码)
    减1后为6,补码表示如下。如果再和7相与,得到的值仍为6。得到的值相当于把7从右边数的第一个1被变成了0

    (6的补码)
    比如6,再减1,为5,补码表示如下

    (5的补码)
    如果再和6相与,得到的值为4。补码表示如下,得到的值相当于把6从右边数的第一个1被变成了0

    如果用负数进行测试,也是一样的结果。
    由此我们可以发现对于数值n,将n - 1后再和n相与,得到的值相当于将n从右边数的第一个1变成0。n的二进制表示中有多少个1,就能变多少次。实现代码如下,时间复杂度优化为O(n中1的个数)

    实现代码

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

    更多题目的完整描述,AC代码,以及解题思路请参考这里

  • 相关阅读:
    最大最小值得判断代码
    等腰三角形的代码及各类代码
    Java ArrayList和Vector、LinkedList与ArrayList、数组(Array)和列表集合(ArrayList)的区别
    Java 集合类的特性
    Java 用程序给出随便大小的10 个数,序号为1-10,按从小到大顺序输出,并输出相应的序号?
    List、Map、Set三个接口,存取元素时,各有什么特点?
    Java 清除数组相同元素
    eclipse导入项目出现叹号处理方法:
    初学者-PHP笔记
    java 对象输入输出流
  • 原文地址:https://www.cnblogs.com/iwiniwin/p/11058255.html
Copyright © 2011-2022 走看看