• 剑指Offer-二进制中的1的个数


    题目

    输入一个整数,输出该数二进制表示中1的个数。

    必备知识-原码、反码与补码

    原码

    将最高位作为符号位(以0代表正,1代表负),其余各位代表数值本身的绝对值(以二进制表示)。

    如果是8位二进制,则:

    +1 的原码为:0000 0001
    -1 的原码为:1000 0001
    

    反码

    • 正数的反码与原码相同。
    • 负数的反码是在其原码的基础上,符号位保持不变,其余各位取反。

    如果是8位二进制,则:

    +1 的反码为:0000 0001
    -1 的反码为:1111 1110
    

    补码

    • 正数的补码与原码相同。
    • 负数的补码是在其原码的基础上,符号位保持不变,其余各位取反,最后再 +1。

    如果是8位二进制,则:

    +1 的补码为:0000 0001
    -1 的补码为:1111 1111
    

    总结

    • 正数的原码、反码与补码是完全相同的,而负数的原码、反码与补码是完全不同的。

    • 反码的出现解决了“正负数相加等于 0”的问题。

    • 补码的出现解决了“两个零 +0 与 -0 存在”的问题,而且可以将符号位和数值位统一处理,加法与减法也可以统一处理。

    解法探析

    解法1

    首先想到的是将二进制数不断右移,这样的话,该数的每一位都会依次移到最右边,每右移一次就将该数和 1 做位与运算,来计算 1 的个数。(由于 1 最右边的一位是 1,其他位都是 0,如果一个整数与 1 做与运算后,结果是 1,就表示该数最右边一位是 1,否则就是 0)

    int NumberOf1(int num)
    {
        int count = 0;
    
        while (num != 0) {
            if ((num & 1) == 1) {
                count++;
            }
    
            num >>= 1;
        }
        
        return count;
    }
    

    上面这种方法没有考虑负数的情况,和正数右移最高位补0不同,负数右移最高位会补1,这样整个数字会变成全1,导致死循环。

    解法2

    既然右移行不通,会导致死循环,那么可以反过来,将1不断左移,然后和目标数做与运算来求 1 的个数。

    int NumberOf1(int num)
    {
        int count = 0;
        unsigned int flag = 1;
    
        while (flag != 0) {
            if ((num & flag) != 0) {
                count++;
            }
    
            flag <<= 1;
        }
    
        return count;
    }
    

    如计算正数 145 的二进制中 1 的个数:

    1001 0001       目标数
    0000 0001       1与目标数做与运算得到的最低位是否为1
    0000 0010       1左移1位,判断其与目标数做与运算得到的次低位是否为1
    0000 0100       1左移2位,判断其与目标数做与运算得到的次次低位是否为1
    ......
    

    解法3

    解法2的时间复杂度为O(num的位数),num有多少位就要循环多少次。可以利用一个小技巧,降低算法的时间复杂度。

    把一个整数减去 1 之后再和原来的整数做位与运算,得到的结果相当于把整数的二进制表示中最右边的 1 变成 0。

    那么一个整数的二进制表示中有多少个 1,就是可以进行多少次这样的操作。

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

    个人主页:

    www.codeapes.cn

  • 相关阅读:
    DevOps平台中的自动化部署
    GitLab的安装及使用教程
    Nginx配置相关
    Shell常用模块
    PostgreSQL基础
    大数据集群监控工具
    大数据常用组件
    kafka知识
    数据结构可视化(包括红黑树动态演示)
    python 周考1
  • 原文地址:https://www.cnblogs.com/codeapes666/p/12239801.html
Copyright © 2020-2023  润新知