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,比特号));
如果(rem1 if(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)