• 整数的二进制表示中1的个数 【微软面试100题 第二十八题】


    题目要求:

      输入一个整数,求该整数的二进制表示中有多少个1.

      比如输入10。因为其二进制表示作为1010,有两个1。因此输出2.

      參考资料:剑指offer第10题、编程之美2.1

    题目分析:

      方法1 除2取余法:一个数a%2的值为0或者1,依据是a的二进制表示的最低位为0。则前面结果为0。【取模和取余的效率比較低。】

      方法2 位操作法:比如a = 0011,a先与0x01&操作,得到一个1。然后a右移为0001。再与0x01&操作。又得到一个1,求和为2。

      方法3 查表法:把全部可能的值放到一个数组中,仅仅要输入一个就直接查表就可以。这样时间复杂度为O(1)。【这样的方法对于8位的比較方便。假设是16位、32位、、、要建立这个数组就很麻烦了。因此这样的方法的算法仅仅适用于须要频繁使用的地方。通过空间复杂度来换取时间复杂度。

      方法4 Hamming weight(汉明重量):先用2位存储邻近2位里面的1的个数,然后合并,用4位表示邻近4位里面的1的个数,再合并、、、

      方法5 减一与法:假如原始数据a = 0011,a&(a-1) = 0001 !=0     0001&(0001-1)=0,则while会进入两次,num=2,即1的个数为2。【仅仅须要运算a表示的二进制中1的个数次就能够求得结果。】  

      方法6 MIT HAKMEM:直接用程序进行解说。


      方法7 动态建表法:假如输入的数字为32位。则分成4*8位,分别求4个8位二进制中1的个数再求和。

         8位二进制中1的个数的求解方法:动态建表。

         以下说一下动态建表的原理:

         依据奇偶性来分析。对于随意一个正整数n:i).假设它是偶数。那么n的二进制中1的个数与n/2中1的个数是同样的,比方4和2的二进制中都有一个1,6和3的二进制中都有两个1。为啥?由于n是由n/2左移一位而来。而移位并不会添加1的个数;ii).假设n是奇数,那么n的二进制中1的个数是n/2中1的个数+1,比方7的二进制中有三个1。7/2 = 3的二进制中有两个1。

    为啥?由于当n是奇数时 ,n相当于n/2左移一位再加1。

    代码实现:

    1.除2取余法

    #include <stdio.h>
    
    int count(unsigned x);
    
    int main(void)
    {
        printf("%d
    ",count(0xffff));
        return 0;
    }
    
    int count(unsigned u)
    { 
        int num = 0;
        while(u)
        {
            if(u % 2 == 1)
                num++;
            u = u/2;
        }
        return num;
    }

    2.位操作法

    #include <stdio.h>
    
    int count(unsigned int x);
    
    int main(void)
    {
        printf("%d
    ",count(0xffff));
        return 0;
    }
    
    int count(unsigned int u)
    { 
        int num = 0;
        while(u)
        {
            num += u&0x01;
            u >>= 1;
        }
        return num;
    }

    3.查表法

    #include <stdio.h>
    
    int count_table[256] = 
    {
        0,1,1,2,1,2,2,3,1,2,2,3,2,2,2,4,1//...
    };
    int count(unsigned char x);
    
    int main(void)
    {
        printf("%d
    ",count(0x0f));
        return 0;
    }
    
    int count(unsigned char u)
    { 
        return count_table[u];
    }

    4.Hamming weight(汉明重量)

    #include <stdio.h>
    
    #define M2  0x55555555
    #define M4  0x33333333
    #define M8  0x0f0f0f0f
    #define M16 0x00ff00ff
    #define M32 0x0000ffff
    int count(unsigned x);
    
    int main(void)
    {
        printf("%d
    ",count(0xffff));
        return 0;
    }
    
    int count(unsigned u)
    { 
        u = (u&M2)  + ((u>>1)&M2);
        u = (u&M4)  + ((u>>2)&M4);
        u = (u&M8)  + ((u>>4)&M8);
        u = (u&M16) + ((u>>8)&M16);
        u = (u&M32) + ((u>>16)&M32);
    
        return u;
    }

    5.减一与法

    #include <stdio.h>
    
    int count(unsigned x);
    
    int main(void)
    {
        printf("%d
    ",count(0xffff));
        return 0;
    }
    
    int count(unsigned u)
    { 
        int num = 0;
        while(u)
        {
            u &= (u-1);
            num++;
        }
        return num;
    }

    6.MIT HAKMEM法

    #include <stdio.h>
    
    int count(unsigned x);
    
    int main(void)
    {
        printf("%d
    ",count(0x80000000));
        return 0;
    }
    
    int count(unsigned u)
    { 
        u = u - (((u >> 1) & 033333333333) + ((u >> 2) & 011111111111));
        u = ((u + (u >> 3)) & 030707070707);
        return u % 63;   
    }

    7.动态建表法

    #include <stdio.h>
    
    int BitCount3(unsigned int n) ;
    
    int main(void)
    {
        printf("bits = %d
    ",BitCount3(0xffff));
        return 0;
    }
    
    int BitCount3(unsigned int n) 
    { 
        // 建表
        unsigned char BitsSetTable256[256] = {0} ; 
        int i;
        unsigned int c =0 ; 
        unsigned char* p;
    
        // 初始化表 
        for (i =0; i <256; i++) 
        { 
            BitsSetTable256[i] = (i &1) + BitsSetTable256[i /2]; 
        } 
    
        // 查表
        printf("%d
    ",&n);
        //这里非常重要。先取地址(此时为32位的地址),然后强制转换为char型(8位)的
        p = (unsigned char*) &n ; 
        printf("&p[0] = %d
    ",&p[0]);
        printf("p[0] = %d
    ",p[0]);
        printf("&p[1] = %d
    ",&p[1]);
        printf("p[1] = %d
    ",p[1]);
    
        c = BitsSetTable256[p[0]] + 
            BitsSetTable256[p[1]] + 
            BitsSetTable256[p[2]] + 
            BitsSetTable256[p[3]]; 
    
        return c ; 
    }


  • 相关阅读:
    拖拽更改窗口大小
    一个窗口移动时,另一个窗口跟随移动
    xcode使用技巧
    同一个解决方案中,多个项目间相互引用,无法打开源文件
    截图时窗口自动识别
    C++使用sqlite时,中文字符显示乱码问题
    sqlite3配置与使用
    duilib控件与属性说明
    xml文件编写
    线程及安全相关
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6962538.html
Copyright © 2020-2023  润新知