Algorithm 计算斐波那契数制中设置的位?
我们知道,每个非负十进制数都可以用斐波那契数之和唯一地表示(这里我们关注的是最小表示,即,在表示一个数时,没有连续的斐波那契数,并且每个斐波那契数在表示中最多取一个) 例如:Algorithm 计算斐波那契数制中设置的位?,algorithm,math,numbers,fibonacci,Algorithm,Math,Numbers,Fibonacci,我们知道,每个非负十进制数都可以用斐波那契数之和唯一地表示(这里我们关注的是最小表示,即,在表示一个数时,没有连续的斐波那契数,并且每个斐波那契数在表示中最多取一个) 例如: 1-> 1 2-> 10 3->100 4->101, here f1=1 , f2=2 and f(n)=f(n-1)+f(n-2); 因此,在斐波那契系统中,每个十进制数都可以表示为二进制序列。如果我们在斐波那契系统中连续写出所有自然数,我们将得到这样的序列:110100101…这称为“自然
1-> 1
2-> 10
3->100
4->101, here f1=1 , f2=2 and f(n)=f(n-1)+f(n-2);
因此,在斐波那契系统中,每个十进制数都可以表示为二进制序列。如果我们在斐波那契系统中连续写出所有自然数,我们将得到这样的序列:110100101…这称为“自然数的斐波那契位序列”
我的任务是计算第1位在序列的前N位中出现的次数。因为N可以取值为1到10^15,所以我可以在不存储斐波那契序列的情况下执行此操作吗
例如:如果N是5,答案是3。这里是O((logn)^3)
让我们计算前N位中适合的数字数量
假设我们有一个函数:
long long number_of_all_bits_in_sequence(long long M);
它计算由不大于M的所有数字创建的“自然数斐波那契位序列”的长度
使用此函数,我们可以使用二进制搜索来查找前N位中适合的数字数量
表示前M个数字的1是多少位
让我们创建一个函数来计算有多少个数字
T(0) = 0
T(1) = 1
T(k) = T(k - 1) + T(k - 2) + F(k - 2)
Mathematica说有一个封闭形式的解决方案,但它看起来很糟糕,而且对于这个polylog(N)来说不需要-时间算法。所以这只是一个算法的初步草图。当上界本身是斐波那契数时,它就起作用了,但我不确定如何将它调整为一般的上界。希望有人能改进这一点
public static int[] fibonacciBitSequenceOfNaturalNumbers(int num) {
int[] setBits = new int[num + 1];
setBits[0] = 0;//anchor case of fib seq
setBits[1] = 1;//anchor case of fib seq
int a = 1, b = 1;//anchor case of fib seq
for (int i = 2; i <= num; i++) {
int c = b;
while (c < i) {
c = a + b;
a = b;
b = c;
}//fib
if (c == i) {
setBits[i] = 1;
continue;
}
c = a;
int tmp = c;//to optimize further, make tmp the fib before a
while (c + tmp != i) {
tmp--;
}
setBits[i] = 1 + setBits[tmp];
}//done
return setBits;
}
总体思路是查看斐波那契编码的结构。以下是前几个数字:
0
1
10
100
101
1000
1001
1010
10000
10001
10010
10100
10101
100000
这些数字中的不变量是,从来没有一对连续的1。给定这个不变量,我们可以使用以下模式从一个数字递增到下一个数字:
00
01
10
现在,看看所有四位数字:
1000
1001
1010
000
001
010
100
101
10000
10001
10010
10100
10101
下一个数字将有五位数字,如下所示:
1011→ 1100→ 一万
需要注意的有趣细节是,四位数字的数量等于最多两位数字的值的数量。事实上,我们只需在最多两位数字的前面加上10就可以得到四位数字
现在,看看三位数:
1000
1001
1010
000
001
010
100
101
10000
10001
10010
10100
10101
看看五位数:
1000
1001
1010
000
001
010
100
101
10000
10001
10010
10100
10101
请注意,五位数只是前缀为10的三位数
这为我们提供了一个非常有趣的方法来计算有多少个1。特别是,如果你看(k+2)-数字,每一个都只是一个前缀为10的k位数字。这意味着,如果所有k位数字中都有B 1s总数,那么只有k+2位的数字中的B总数等于B加上k位数字的数量,因为我们只是在重放序列,每个数字前面加上一个额外的1
我们可以利用这一点来计算Fibonacci编码中最多有k位数的1的数量。诀窍如下-如果我们跟踪每一位数
- N(d+2)=N(d)+N(d+1)。这是因为最多d+2位数的数字数是最多d+1位数(N(d+1))的数字数,再加上在带有d位数(N(d))的数字前加上10所形成的数字
- B(d+2)=B(d+1)+B(d)+N(d)(最大长度为d+2的数字中的1位总数是最大长度为d+1的数字中的1位总数,加上我们仅从d+2位数中获得的额外数字)
d N(d) B(d)
---------------------
1 2 1
2 3 2
3 5 5
4 8 10
5 13 20
我们可以检查一下。对于1位数字,总共使用了1位。对于2位数字,有两个1(1和10)。对于3位数字,有5个1(1,10,100,101)。对于4位数字,有10个1(之前的5个,加上1000,1001,1010).向外扩展会得到我们想要的顺序
这是非常容易计算的-我们可以计算
public static void main(String... args) {
int[] arr = fibonacciBitSequenceOfNaturalNumbers(23);
//print result
for(int i=1; i<arr.length; i++)
System.out.format("%d has %d%n", i, arr[i]);
}
1 has 1
2 has 1
3 has 1
4 has 2
5 has 1
6 has 2
7 has 2
8 has 1
9 has 2
10 has 2
11 has 2
12 has 3
13 has 1
14 has 2
15 has 2
16 has 2
17 has 3
18 has 2
19 has 3
20 has 3
21 has 1
22 has 2
23 has 2
//to return total number of set between 1 and n inclusive
//instead of returning as in original post, replace with this code
int total = 0;
for(int i: setBits)
total+=i;
return total;
0
1
10
100
101
1000
1001
1010 <-- we want to count ones up to here
10000
000
001
010
dp[i] = fib[i-2] + dp[i-2] + dp[i-1];
0
1
10
100
101
1000
1001 <-- we want to count ones up to here
1010
0000000000