Algorithm 查找从1到n的设置位总数

Algorithm 查找从1到n的设置位总数,algorithm,Algorithm,编写一个算法,以查找F(n)设置为1的位数,对于任何给定的n值,在从1到n的所有数字中 复杂性应为O(logn) 例如: 1: 001 2: 010 3: 011 4: 100 5: 101 6: 110 所以 我只能设计一个O(n)算法。让k为n所需的位数 对于0,…,2^(k-1)-1每个位正好是数字的一半,因此我们有(k-1)*2^(k-1)/2=(k-1)*2^(k-2)位。我们只需要检查比2^(k-1)-1更大的数字是怎么回事 对于MSB的n-2^(k-1)-1位,我们也有“up”

编写一个算法,以查找
F(n)
设置为1的位数,对于任何给定的n值,在从1到n的所有数字中

复杂性应为
O(logn)

例如:

1: 001
2: 010
3: 011
4: 100
5: 101
6: 110
所以


我只能设计一个
O(n)
算法。

k
n
所需的位数


对于
0,…,2^(k-1)-1
每个位正好是数字的一半,因此我们有
(k-1)*2^(k-1)/2=(k-1)*2^(k-2)
位。我们只需要检查比
2^(k-1)-1更大的数字是怎么回事

对于MSB的
n-2^(k-1)-1
位,我们也有“up”

因此,我们可以导出递归函数:

f(n) = (k-1)*2^(k-2) + n-(2^(k-1)-1) + f(n-(2^(k-1)))
           ^               ^            ^
         first            MSBs        recursive call for 
       2^(k-1)-1                      n-2^(k-1) highest numbers
        numbers
其中base是
f(0)=0
f(2^k)=k*2^(k-1)+1
[正如我们前面所看到的,我们确切地知道
2^(k-1)-1
,我们只需要为
2^k
的MSB添加1-]

由于发送到
f
的值在每次迭代中至少减少一半,因此我们得到
O(logn)
的总数,如果
n=2^k-1,那么f(n)=k*(n+1)/2


对于一般的
n
,让
m
为最大数,使得
m=2^k-1
m解决这类问题的方法是写出前几个值,并寻找模式

Number binary # bits set F(n) 1 0001 1 1 2 0010 1 2 3 0011 2 4 4 0100 1 5 5 0101 2 7 6 0110 2 9 7 0111 3 12 8 1000 1 13 9 1001 2 15 10 1010 2 17 11 1011 3 20 12 1100 2 22 13 1101 3 25 14 1110 3 28 15 1111 4 32
因此,对于
8而言,快速搜索序列F的值将导致该整数序列

在那里我发现了一个公式: a(0)=0,a(2n)=a(n)+a(n-1)+n,a(2n+1)=2a(n)+n+1(a与F相同,因为我只是从oeis复制公式)

可以用来计算log(n)中的a(n)

这是我的样本C++代码:

memset(cache, -1, sizeof(cache))
cache[0] = 0

int f(int n)
    if cache[n] != -1 return cache[n];
    cache[n] = n % 2 ? (2 * f(n / 2) + n / 2 + 1) : (f(n / 2) + f(n / 2 - 1) + n / 2)
又短又甜

 public static int countbits(int num){
    int count=0, n;
    while(num > 0){
        n=0;
        while(num >= 1<<(n+1))
            n++;
        num -= 1<<n;
        count += (num + 1 + (1<<(n-1))*n);
    }
    return count;
}//countbis
公共静态int countbits(int num){
整数计数=0,n;
while(num>0){
n=0;
当(num>=1时,考虑以下因素:

0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
如果要查找从1到14(1110)的设置位总数 很少观察到:

  • 0th
    位(LSB)
    1
    位每两位出现一次(垂直查看),因此设置位的数量=
    n/2+
    1
    如果
    n的0th位为1
    0
  • 第1位:每4位出现2个连续的1(沿所有数字垂直查看第1位)
    1st
    位位置中的设置位数=
    (n/4*2)+1
    (因为
    1st
    位是一个集合,否则
    0
  • 2nd
    位:
    4
    连续
    1s
    每隔
    8
    位出现一次(这个有点棘手) 第二位置的设置位数=
    (n/8*4)+1
    (因为设置了
    2nd
    位,否则
    0
    +((n%8)%(8/2))
    最后一项是包括第一个
    (n/8)
    位组之外的
    1
    的数量(
    14/8=1
    只考虑
    1
    组,即
    4
    8
    位中设置位。我们需要包括在最后一个
    14-8=6
    位中找到的
    1s
  • 3rd
    位:
    8
    16位出现一个连续的1s(与上面类似)
    
    3rd
    位置的设置位数=
    (n/16*8)+1
    (由于设置了
    3rd
    位,否则
    0
    +((n%16)%(16/2))
  • 所以我们对一个数的每一位进行计算。
    一个数字包含
    log2(n)
    位。因此,当我们对
    n
    的所有位置进行上述迭代并在每个步骤添加所有设置位时,我们在
    O(logn)
    步骤中得到答案

    private static int[] findx(int i) {
        //find the biggest power of two number that is smaller than i
        int c = 0;
        int pow2 = 1;
        while((pow2<< 1) <= i) {
            c++;
            pow2 = pow2 << 1;
        }
        return new int[] {c, pow2};
    }
    
    public static int TotalBits2(int number) {
        if(number == 0) {
            return 0;
        }
        int[] xAndPow = findx(number);
        int x = xAndPow[0];
        return x*(xAndPow[1] >> 1) + TotalBits2(number - xAndPow[1]) + number - xAndPow[1] + 1;
    }
    
    private static int[]findx(int i){
    //找出比i小的两个数的最大幂
    int c=0;
    int-pow2=1;
    
    而((pow2这是用java编码的…
    逻辑:假设数字是34,二进制等于ant是10010,可以写成10000+10。 10000有4个零,所以在这个数字之前所有1的计数都是2^4(原因如下)。所以计数是2^4+2^1+1(数字本身)。所以答案是35。
    *对于二进制数10000。填充4位的总组合为2*2*2*2x2(一或零)。因此,1的总组合为2*2*2*2

    public static int getOnesCount(int number) {
        String binary = Integer.toBinaryString(number);
        return getOnesCount(binary);
    }
    
    private static int getOnesCount(String binary) {
        int i = binary.length();
    
        if (i>0 && binary.charAt(0) == '1') {
            return gePowerof2(i) + getOnesCount(binary.substring(1));
        }else if(i==0)
            return 1;
        else
            return getOnesCount(binary.substring(1));
    
    }
    //can be replaced with any default power function
    private static int gePowerof2(int i){
        int count = 1;
        while(i>1){
            count*=2;
            i--;
        }
        return count;
    }
    

    顺便说一句,这个问题也可以通过查表的方法来解决。预先计算0-255之间的设置位数并存储它。然后,我们可以通过将给定的数字分成两部分(每个部分8位)来计算任意数字中的设置位数。对于每个部分,我们可以在第一步中形成的计数数组中查找。例如,如果有一个16位的数字,比如

    x=1100110001011100
    ,这里的设置位数=第一个字节中的设置位数+第二个字节中的设置位数。因此,为了获得第一个字节

    y=(x&0xff)
    z=(x>>8)和(0xff)
    总设置位=计数[y]+计数[z]


    此方法也将在O(n)中运行。

    不确定是否要晚回复,但以下是我的发现

    尝试使用以下方法解决该问题,对于数字N,每个比特号(从LSB到MSB,假设LSB从比特号1开始,并随下一个比特值递增)的比特集数量可以计算为,(N/(2 topower bitno)*(2 topower bitno-1)+{(N%(2 topower bitno))-[(2 topower bitno-1)-1]}

    已经为它编写了递归函数C/C++请检查。我不确定,但我认为它的复杂性是log(N)。传递函数2参数,我们希望计算位的数字(否)和LSB的第二个开始计数,值1

    int recursiveBitsCal(int no, int bitno){
    int res = int(no/pow(2,bitno))*int(pow(2,bitno-1));
    int rem1 = int(pow(2,bitno-1)) -1;
    int rem = no % int(pow(2,bitno));
    if (rem1 < rem) res += rem -rem1;
    if ( res <= 0 )
        return 0;
    else
        return res + recursiveBitsCal(no, bitno+1);
    }
    
    int recursiveBitsCal(int-no,int-bitno){
    int res=int(no/pow(2,比特号))*int(pow(2,比特号-1));
    int rem1=int(功率(2,比特号-1))-1;
    int rem=无%int(功率(2,比特号));
    如果(rem1if(res这是我的解决方案。时间复杂度:O(logn)

    int countsetbit(int n)
    {
    n++;
    int-powerOf2=2;
    int-setBitsCount=n/2;
    
    而(powerOf2我知道这篇文章发表得很晚
    private static int[] findx(int i) {
        //find the biggest power of two number that is smaller than i
        int c = 0;
        int pow2 = 1;
        while((pow2<< 1) <= i) {
            c++;
            pow2 = pow2 << 1;
        }
        return new int[] {c, pow2};
    }
    
    public static int TotalBits2(int number) {
        if(number == 0) {
            return 0;
        }
        int[] xAndPow = findx(number);
        int x = xAndPow[0];
        return x*(xAndPow[1] >> 1) + TotalBits2(number - xAndPow[1]) + number - xAndPow[1] + 1;
    }
    
    public static int getOnesCount(int number) {
        String binary = Integer.toBinaryString(number);
        return getOnesCount(binary);
    }
    
    private static int getOnesCount(String binary) {
        int i = binary.length();
    
        if (i>0 && binary.charAt(0) == '1') {
            return gePowerof2(i) + getOnesCount(binary.substring(1));
        }else if(i==0)
            return 1;
        else
            return getOnesCount(binary.substring(1));
    
    }
    //can be replaced with any default power function
    private static int gePowerof2(int i){
        int count = 1;
        while(i>1){
            count*=2;
            i--;
        }
        return count;
    }
    
    int recursiveBitsCal(int no, int bitno){
    int res = int(no/pow(2,bitno))*int(pow(2,bitno-1));
    int rem1 = int(pow(2,bitno-1)) -1;
    int rem = no % int(pow(2,bitno));
    if (rem1 < rem) res += rem -rem1;
    if ( res <= 0 )
        return 0;
    else
        return res + recursiveBitsCal(no, bitno+1);
    }
    
    public int countSetBits(int n){
        int count=0;
        while(n>0){
            int i= (int)(Math.log10(n)/Math.log10(2));
            count+= Math.pow(2, i-1)*i;
            count+= n-Math.pow(2, i)+1;
            n-= Math.pow(2, i);
        }
        return count;
    }
    
    for i in range(int(input())):
        n=int(input())
        c=0
        m=13
    
        if n==0:
            print(c)
        while n%8!=0 or n!=0:
            t=bin(n)[2:]
            c+=t.count('1')
            n=n-1
        if n!=0:
            j=n//8
            if j==1:
                c+=m
            else:
                c+=m+((j-1)*7)
        print(c)        
    
    int countSetBits(int n)
    {
        n++;
        int powerOf2 = 2;
        int setBitsCount = n/2;
        while (powerOf2 <= n)
        {
            int numbersOfPairsOfZerosAndOnes = n/powerOf2;
            setBitsCount += (numbersOfPairsOfZerosAndOnes/2) * powerOf2;
            setBitsCount += (numbersOfPairsOfZerosAndOnes&1) ? (n%powerOf2) : 0;
            powerOf2 <<= 1;
        }
        return setBitsCount;
    }
    
    static int countSetBitWithinRange(int n)
    {
        int x = n + 1, index = 0, count = 0;
        int numberOfOnesInAGroup = (int)Math.pow(2, index);
        while(x >= numberOfOnesInAGroup)
        {
            int countOfZeroOnePairs = (x / numberOfOnesInAGroup);
            int numberOfPairsOfZerosAndOnes = countOfZeroOnePairs / 2;
            int numberOfSetBits = numberOfPairsOfZerosAndOnes * numberOfOnesInAGroup;
            //If countOfZeroOnePairs is even then the pairs are complete else there will be ones that do not have a corresponding zeros pair
            int remainder = (countOfZeroOnePairs % 2 == 1) ? (x % numberOfOnesInAGroup) : 0;
            count = count + numberOfSetBits + remainder;
            numberOfOnesInAGroup = 1 << ++index;
        }
        return count;
    }
    
    x = int(input("Any number:\n"))
    y = (bin(x))
    print(y)
    v = len(y) -2
    print(v)