• 求二进制中1的个数(编程之美2.1)


    行文脉络

    1. 解法一——除法
    2. 解法二——移位
    3. 解法三——高效移位
    4. 解法四——查表
    5. 扩展问题——异或后转化为该问题

    对于一个字节(8bit)的变量,求其二进制“1”的个数。例如6(二进制0000 0110)“1”的个数为2,要求算法效率尽量高。

    解法一

    对于二进制数来说,除一个2,就少一位,可以判断这个少的位来确定“1”的个数。

    例如:6(0000 0110)

    0000 0110 / 2 = 0000 0011     ----少的一位为0

    0000 0011 / 2 = 0000 0001     ----少的一位为1

    0000 0001 / 2 = 0000 0000     ----少的一位为1

    操作数数已经为0,到此结束

    参考代码

    int Count_1(int val)
    {
        int num = 0;
        while(val)
        {
            if(val % 2 != 0)   //用取模获得去除的一位
                ++num;
            val /= 2;
        }
        return num;
    }

    性能:时间复杂度O(log2v),即二进制数的位数;空间复杂度O(1)

    解法二

    对于二进制数来说,除法是用移位完成。

    例如:6(0000 0110)

    0000 0110 >> 1 = 0000 0011     ----少的一位为0

    0000 0011 >> 1 = 0000 0001     ----少的一位为1

    0000 0001 >> 1 = 0000 0000     ----少的一位为1

    操作数数已经为0,到此结束

    参考代码

    int Count_2(int val)
    {
        int num = 0;
        while(val)
        {
            if(val & 1 != 0)   //用与1与获得移除的一位
                ++num;
            val >>= 1;
        }
        return num;
    }

    性能:时间复杂度O(log2v),即二进制数的位数;空间复杂度O(1)

    解法三

    对于上述算法,有个问题,比如1000 0000,大把的时间用在没用的0上,最好寻求一种直接判断“1的个数。

    通过观察可以找到规律:对于数a, a = a & (a-1)就可以去除a的最后一个1

    例如:6(0000 0110)

    0000 0110 & 0000 0101 = 0000 0100     

    0000 0100 & 0000 0011 = 0000 0000

    操作数数已经为0,到此结束

    参考代码

    int Count_3(int val)
    {
        int num = 0;
        while(val)
        {
            val &= (val -1);
            ++num;
        }
        return num;
    }

    性能:时间复杂度O(M),即二进制中“1”的个数,空间复杂度O(1)

    解法四

    查表法,把0~255这256个数的结果全部存储在数组中,val直接作为下标,countTable[val]即为结果。典型的用空间换时间。

    参考代码

    int Count_5(int val)
    {
        int countTable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
        return countTable[val];
    }

    性能:时间复杂度:O(1), 空间复杂度O(N)

    整个程序执行参考

    #include<iostream>
    using namespace std;
    
    int Count_1(int val)
    {
        int num = 0;
        while(val)
        {
            if(val % 2 != 0)
                ++num;
            val /= 2;
        }
        return num;
    }
    
    int Count_2(int val)
    {
        int num = 0;
        while(val)
        {
            if(val & 1 != 0)
                ++num;
            val >>= 1;
        }
        return num;
    }
    
    int Count_3(int val)
    {
        int num = 0;
        while(val)
        {
            val &= (val -1);
                ++num;
        }
        return num;
    }
    int Count_5(int val)
    {
        int countTable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
        return countTable[val];
    }
    
    int main()
    {
        int a = 6, b = 255;
        cout << "Num of 1:" << Count_1(a) << endl; 
        cout << "Num of 1:" << Count_2(a) << endl; 
        cout << "Num of 1:" << Count_3(a) << endl; 
        cout << "Num of 1:" << Count_5(b) << endl; 
        cout << "Num of 1:" << Count_1(b) << endl; 
        cout << "Num of 1:" << Count_2(b) << endl; 
        cout << "Num of 1:" << Count_3(b) << endl; 
        cout << "Num of 1:" << Count_5(b) << endl; 
    }
    View Code

    结果

    扩展问题

    1. 给定两个正整数(二进制表示)A、B,如何快速找出A和B二进制表示中不同位数的个数。

      思路

      首先A和B进行异或操作,然后求得到的结果中1的个数(此问题)。

    2. 判断一个数是否是2的幂

    bool powerof2(int n)
    {
        return ((n & (n-1)) == 0);
    }
  • 相关阅读:
    [HAOI2008]硬币购物
    [SCOI2005]骑士精神
    [ZJOI2007]最大半联通子图
    [HAOI2007]反素数
    [SCOI2005]繁忙的都市
    小凯的疑惑
    5月16日vj题解
    周六题目前四题详解
    Codeforces Round #629 (Div. 3)做题记录
    Codeforces Round #570 (Div. 3) B. Equalize Prices
  • 原文地址:https://www.cnblogs.com/kaituorensheng/p/3562076.html
Copyright © 2020-2023  润新知