如何在o(logn)中找到第n个非Fibonacci数
非斐波纳契数是:4,6,7,9,10 ....
下面的函数给出给定的n
static int nonFibonacci(int n){
int a=1,b=2,c=3;
while(n>0){
a=b;
b=c;
c=a+b;
n-=(a-1);
}
n+=(a-1);
return (n+b);
}
它给出了正确答案,但我想优化它,使用矩阵乘法可以在o(logn)中找到斐波纳契数如何应用该属性来找到第n个非斐波纳契数。
答案 0 :(得分:1)
您的代码段中的算法不是O(n)
,因为斐波那契数列呈指数级增长。因此,您需要O(log n)
步骤才能比n更大。以下(以及非常简单的“基准”)似乎确认您的代码已经具有正确的复杂性:
public class Benchmark {
public static void main(String[] args) {
long n = 2;
for (int i=0 ; i<62 ; i++, n *= 2) {
long executionTimeNanos = timedExecution(n);
System.out.println(n + " " + executionTimeNanos + " " + executionTimeNanos/Math.log(n));
}
}
private static long timedExecution(long n) {
long start = System.nanoTime();
nonFibonacci(n);
return System.nanoTime() - start;
}
private static long nonFibonacci(long n) {
long a = 1, b = 2, c = 3;
while (n > 0) {
a = b;
b = c;
c = a + b;
n -= (a - 1);
}
n += (a - 1);
return (n + b);
}
}
输出:
2 3421 4935.459734881144
4 2566 1850.97773746054
8 855 411.16808665335464
16 2566 925.48886873027
32 1283 370.195547492108
64 855 205.58404332667732
128 1283 264.4253910657915
256 1283 231.3722171825675
512 856 137.21632833343918
1024 1283 185.097773746054
2048 1711 224.40465590554695
4096 1711 205.70426791341805
8192 1283 142.38290288158
16384 1710 176.2148942800091
32768 1283 123.39851583070268
65536 1283 115.68610859128376
131072 1283 108.88104338003177
262144 1710 137.05602888445154
524288 1711 129.91848499794824
1048576 1283 92.548886873027
2097152 1710 117.47659618667274
4194304 1711 112.20232795277347
8388608 1710 107.26123999652728
16777216 1711 102.85213395670903
33554432 1711 98.73804859844066
67108864 1710 94.88494307385106
134217728 1710 91.37068592296768
268435456 2138 110.16007133645014
536870912 2138 106.36144818691737
1073741824 1711 82.28170716536722
2147483648 2138 99.49941927163238
4294967296 2566 115.68610859128376
8589934592 2138 93.46915143698799
17179869184 2993 126.99959580531375
34359738368 2565 105.72893656800545
68719476736 2138 85.68005548390566
137438953472 2566 100.0528506735427
274877906944 2566 97.41988091897579
549755813888 6415 237.30483813596666
1099511627776 2138 77.11204993551509
2199023255552 2566 90.29159694929464
4398046511104 2138 73.44004755763342
8796093022208 2566 86.09198778886233
17592186044416 2566 84.13535170275182
35184372088832 2566 82.26567722046845
70368744177664 2566 80.47729293306696
140737488355328 2566 78.76501010470383
281474976710656 2565 77.09401624750399
562949953421312 2566 75.55011173308327
1125899906842624 2994 86.38857904843113
2251799813685248 2994 84.69468534159914
4503599627370496 2993 83.03819725732053
9007199254740992 2994 81.498659479652
18014398509481984 5132 137.10946203411407
36028797018963968 2994 78.53507186221012
72057594037927936 2993 77.10689745322621
144115188075855872 2993 75.7541448663275
288230376151711744 13257 329.7553130528446
576460752303423488 3421 83.65185991323972
1152921504606846976 2994 71.99048254035928
2305843009213693952 3421 80.9091759816581
4611686018427387904 3421 79.60418927227651
如您所见,即使对于n = 2 ^ 62,执行时间仅为3421纳秒,这显然不是线性的。 executionTime/log(n)
的比例在最后看起来非常稳定,大约为80,这使得您的解决方案成为O(n)
。
我认为我们在开始时观察到的变化是由于Fibonacci系列的第二项。确实,Fn = (phi^n - psi^n)/sqrt(5) with phi = (1 + sqrt(5))/2 > 1 and psi = (1 - sqrt(5))/2 < 1
。当n很小时,psi^n
仍然会影响结果,但因为它小于1,当n很大时它会变得非常小,这就是为什么它在结尾而不是在开始时得到对数的原因。
答案 1 :(得分:1)
显示我们的目标值是( n + k ),其中 F k <这是微不足道的/ em>是最大的Fibonacci数,它比我们的目标小。因此,我们需要做的就是找到 k 。
您可以使用二进制搜索(使用矩阵乘法)在O(log log n)时间内执行此操作。
您可以在O(1)时间内通过按 k 反转 F k 的closed-form expression来执行此操作。