• 338.比特位计数


    给你一个整数n,对于0<=i<=n,计算其二进制中1的个数,返回一个长度为n+1的数组ans作为答案

    示例 1:

    输入:n = 2

    输出:[0,1,1]

    解释:

    0 --> 0

    1 --> 1

    2 --> 10

    示例 2:

    输入:n = 5

    输出:[0,1,1,2,1,2]

    解释:

    0 --> 0

    1 --> 1

    2 --> 10

    3 --> 11

    4 --> 100

    5 --> 101

    方法一:Brian Kernighan 算法

    最直观的做法是对从 00 到 nn 的每个整数直接计算「一比特数」。每个int 型的数都可以用 32 位二进制数表示,只要遍历其二进制表示的每一位即可得到 1 的数目。Brian Kernighan 算法,可以在一定程度上进一步提升计算速度。Brian Kernighan 算法的原理是:对于任意整数 x,令 x=x & (x−1),该运算将 x 的二进制表示的最后一个 1 变成 0。因此,对 x 重复该操作,直到 x 变成 0,则操作次数即为x 的「一比特数」。对于给定的 n,计算从 0 到 n 的每个整数的「一比特数」的时间都不会超过 O(logn),因此总时间复杂度为 O(nlogn)。


    int coutnoes (int x)

    {
        int ones=0;
        while(x>0)
        {
            x&=x-1;
            ones++;
        }
        return ones;
    }
    int* countBits(int n, int* returnSize){
        int *res=(int *)malloc(sizeof(int)*(n+1));
        *returnSize=n+1;
        for (int i=0;i<=n;i++)
        {
            res[i]=coutnoes(i);
        }
        return res;
    }

    时间复杂度:O(nlogn)

    空间复杂度:O(1)


    解法二:动态规划——最高有效位

    方法一需要对每个整数使用O(logn)的时间计算【—比特数】。可以换一个思路,当计算i的【—比特数】时,如果存在0<=j<=i,j的【—比特数】已知,且i和j相比,i的二进制表示之多一个1,则可以快速得到i的—比特数。

    令bits[i]表示i的[-比特数],则上述关系表示为bits[i]=bits[j]+1。

    对于正整数x,如果可以知道最大的正整数y,使得y<=x,且y是2的整数次幂,则y的二进制表示中只有最高为是1,其余是0,此时称y为x的[最高有效位]。令z=x-y,显然0<=z

    为了判断一个正整数是不是2的整数次幂,可以利用方法一中提到的按位与运算性质。如果正整数 y 是 2 的整数次幂,则 y 的二进制表示中只有最高位是 1,其余都是 0,因此 y&(y-1)=0。由此可见,正整数 y 是 2 的整数次幂,当且仅当 y & (y−1)=0。

    显然,0 的「一比特数」为 0。使highBit 表示当前的最高有效位,遍历从 1 到 n的每个正整数 i,进行如下操作。如果 i&(i-1)=0,则令highBit=i,更新当前的最高有效位。i 比 i−highBit 的「一比特数」多 1,由于是从小到大遍历每个整数,因此遍历到 i 时,i−highBit 的「一比特数」已知,bits[i]=bits[i−highBit]+1。


    int* countBits(int n, int* returnSize){

        int highbit=0;

        int *bit=(int *)malloc(sizeof(int)*(n+1));

        *returnSize=n+1;

        bit[0]=0;

        for (int i=1;i<=n;i++)

        {

            if ((i&(i-1))==0)

            {

                highbit=i;

            }

            bit[i]=bit[i-highbit]+1;

        }

        return bit;

    }

    时间复杂度:O(n)

    空间复杂度:O(1)


    方法三:动态规划——最低设置位

    定义正整数 x 的「最低设置位」为 x 的二进制表示中的最低的 1 所在位。例如,1010 的二进制表示是 1010_(2)  10(2),其最低设置位为 2,对应的二进制表示是 10_{(2)}10 (2) 。

    令y=x & (x−1),则 y 为将 x 的最低设置位从 1 变成 0 之后的数,显然 0≤y

    int* countBits(int n, int* returnSize) {

        int* bits = malloc(sizeof(int) * (n + 1));
        *returnSize = n + 1;
        bits[0] = 0;
        for (int i = 1; i <= n; i++) {
            bits[i] = bits[i & (i - 1)] + 1;
        }
        return bits;
    }

    时间复杂度:O(n)

    空间复杂度:O(1)

  • 相关阅读:
    实时聊天系统PHP
    java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码
    【笔记】Python网络爬虫与信息提取
    Servlet规范之Web应用
    Python集合类型详解(一)——集合定义与集合操作符
    自制操作系统系列(一):显示hello world开始旅程
    wget用法随笔
    算法 | 刷题日记
    git撤回多个push到远程仓库的commit
    2.最长公共子串
  • 原文地址:https://blog.csdn.net/qq_70799748/article/details/125897356