反Fibonacci算法?

时间:2011-03-02 02:29:21

标签: algorithm math fibonacci

有许多方法可以计算任意n的F(n),其中很多都有很大的运行时和内存使用率。

但是,假设我想问相反的问题:

  

给定N的F(n)> 2,什么是n?

(由于F(1)= F(2)= 1并且没有明确的逆,因此n> 2限制在那里。

解决此问题的最有效方法是什么?通过枚举斐波纳契数并在达到目标数时停止,可以很容易地在线性时间内完成此操作,但有没有比这更快的方法呢?

编辑:目前,此处发布的最佳解决方案使用O(log n)内存在O(log n)时间运行,假设数学运算在O(1)中运行并且是机器字可以在O(1)空间中保存任何数字。我很好奇是否可以降低内存要求,因为你可以使用O(1)空间计算斐波纳契数。

10 个答案:

答案 0 :(得分:51)

由于OP已经询问了不涉及任何浮点计算的矩阵解决方案,所以在这里。假设数值运算具有O(logn)复杂度,我们可以通过这种方式实现O(1)复杂度。

让我们采用具有以下结构的2x2矩阵A

1 1
1 0

现在考虑向量(8, 5),存储两个连续的斐波纳契数。如果你将它乘以这个矩阵,你将获得(8*1 + 5*1, 8*1 + 5*0) = (13, 8) - 下一个斐波纳契数 如果我们概括,A^n * (1, 0) = (f(n), f(n - 1))

实际算法需要两个步骤。

  1. 计算A^2A^4A^8等,直到我们通过所需的号码。
  2. 使用n
  3. 的计算能力,按A进行二进制搜索

    在旁注中,f(n) = k1*f(n-1) + k2*f(n-2) + k3*f(n-3) + .. + kt*f(n-t)形式的任何序列都可以这样呈现。

答案 1 :(得分:39)

Wikipedia将结果显示为

n(F) = Floor[ Log(F Sqrt(5) + 1/2)/Log(Phi)]

Phi是黄金比例。

答案 2 :(得分:12)

如果您可以轻松地解释二进制中的F(n),

formula

您可能对常数1.7和1.1持怀疑态度。这些工作是因为d * 1.44042009041 + C永远不会非常接近整数。

如果有兴趣,我明天可以发布一个推导。

这是一张n = 2到91的表格,它显示了地板之前的公式结果:

 n  formula w/o floor     F(n) F(n) in binary

 2  2.540                    1 1
 3  3.981                    2 10
 4  4.581                    3 11
 5  5.421                    5 101
 6  6.862                    8 1000
 7  7.462                   13 1101
 8  8.302                   21 10101
 9  9.743                   34 100010
10 10.343                   55 110111
11 11.183                   89 1011001
12 12.623                  144 10010000
13 13.223                  233 11101001
14 14.064                  377 101111001
15 15.504                  610 1001100010
16 16.104                  987 1111011011
17 17.545                 1597 11000111101
18 18.385                 2584 101000011000
19 19.825                 4181 1000001010101
20 20.425                 6765 1101001101101
21 21.266                10946 10101011000010
22 22.706                17711 100010100101111
23 23.306                28657 110111111110001
24 24.147                46368 1011010100100000
25 25.587                75025 10010010100010001
26 26.187               121393 11101101000110001
27 27.028               196418 101111111101000010
28 28.468               317811 1001101100101110011
29 29.068               514229 1111101100010110101
30 30.508               832040 11001011001000101000
31 31.349              1346269 101001000101011011101
32 32.789              2178309 1000010011110100000101
33 33.389              3524578 1101011100011111100010
34 34.230              5702887 10101110000010011100111
35 35.670              9227465 100011001100110011001001
36 36.270             14930352 111000111101000110110000
37 37.111             24157817 1011100001001111001111001
38 38.551             39088169 10010101000111000000101001
39 39.151             63245986 11110001010000111010100010
40 40.591            102334155 110000110010111111011001011
41 41.432            165580141 1001110111101000110101101101
42 42.032            267914296 1111111110000000110000111000
43 43.472            433494437 11001110101101001100110100101
44 44.313            701408733 101001110011101010010111011101
45 45.753           1134903170 1000011101001010011111110000010
46 46.353           1836311903 1101101011100111110010101011111
47 47.193           2971215073 10110001000110010010010011100001
48 48.634           4807526976 100011110100011010000101001000000
49 49.234           7778742049 111001111101001100010111100100001
50 50.074          12586269025 1011101110001100110011100101100001
51 51.515          20365011074 10010111101110110010110100010000010
52 52.115          32951280099 11110101100000011001010000111100011
53 53.555          53316291173 110001101001111001100000101001100101
54 54.396          86267571272 1010000010101111100101010110001001000
55 55.836         139583862445 10000001111111110110001011011010101101
56 56.436         225851433717 11010010010101110010110110001011110101
57 57.276         365435296162 101010100010101101001000001100110100010
58 58.717         591286729879 1000100110101011011011110111110010010111
59 59.317         956722026041 1101111011000001000100111001011000111001
60 60.157        1548008755920 10110100001101100100000110001001011010000
61 61.598        2504730781961 100100011100101101100101101010100100001001
62 62.198        4052739537881 111010111110011010000110011011101111011001
63 63.038        6557470319842 1011111011011000111101100000110010011100010
64 64.478       10610209857723 10011010011001100001110010100010000010111011
65 65.078       17167680177565 11111001110100101001011110101000010110011101
66 66.519       27777890035288 110010100001110001011010001001010011001011000
67 67.359       44945570212853 1010001110000010110100101111110010101111110101
68 68.800       72723460248141 10000100010010001000000000000111101001001001101
69 69.400      117669030460994 11010110000010011110100110000101111111001000010
70 70.240      190392490709135 101011010010100100110100110001101101000010001111
71 71.681      308061521170129 1000110000010111000101001100010011100111011010001
72 72.281      498454011879264 1110001010101011101011110010100001001111101100000
73 73.121      806515533049393 10110111011000010110000111110110100110111000110001
74 74.561     1304969544928657 100101000101101110011100110001010110000110110010001
75 75.161     2111485077978050 111100000000110001001101110000001010111101111000010
76 76.602     3416454622906707 1100001000110011111101010100001100001000100101010011
77 77.442     5527939700884757 10011101000111010000111000010001101100000010100010101
78 78.042     8944394323791464 11111110001101110000100010110011001101000111001101000
79 79.483    14472334024676221 110011011010101000001011011000100111001001001101111101
80 80.323    23416728348467685 1010011001100010110001111101111000000110010000111100101
81 81.764    37889062373143906 10000110100110111110011011000111100111111011010101100010
82 82.364    61305790721611591 11011001110011010100101010110110101000101101011101000111
83 83.204    99194853094755497 101100000011010010011000101111110010000101000110010101001
84 84.644   160500643816367088 1000111010001101100111110000110100111001010110001111110000
85 85.244   259695496911122585 1110011010100111111010110110110011001001111111000010011001
86 86.085   420196140727489673 10111010100110101100010100111101000000011010101010010001001
87 87.525   679891637638612258 100101101111011101011101011110011011001101010100010100100010
88 88.125  1100087778366101931 111101000100010011000000000110000011010000101001100110101011
89 89.566  1779979416004714189 1100010110011110000011101100100011110011101111101111011001101
90 90.406  2880067194370816120 10011111111000000011011101101010100001101110100111100001111000
91 91.846  4660046610375530309 100000010101011110011111011001111000000001100100101011101000101

答案 3 :(得分:11)

通过计算无界词来衡量内存使用情况有点傻,但只要是模型,就会有一个类似于Nikita Rybak的 O(log n)时间,O(1)字解决方案实质上通过Zeckendorf representation计算n,{{3}}基于斐波纳契数(YO DAWG)。

定义矩阵

      1  1
A  =       ,
      1  0

满足

        F(m + 1)    F(m)
A^m  =                      .
          F(m)    F(m - 1)

我们将使用序列A^(2^k)而不是序列A^F(k)。后一个序列具有我们可以使用矩阵乘法

向前移动的特性
A^F(k + 1) = A^F(k - 1) * A^F(k)

并向后使用矩阵求逆和乘法

A^F(k - 1) = A^F(k + 1) (A^F(k))^-1,

因此我们可以构建一个双向迭代器,只有 8 six 十二个字,假设我们将所有内容存储为有理数(以避免假设存在单位成本除)。其余的只是调整这个O(1)空间算法来寻找Zeckendorf表示。

def zeck(n):
    a, b = (0, 1)
    while b < n:
        a, b = (b, a + b)
    yield a
    n1 = a
    while n1 < n:
        a, b = (b - a, a)
        if n1 + a <= n:
            yield a
            n1 += a
            a, b = (b - a, a)

>>> list(zeck(0))
[0]
>>> list(zeck(2))
[1, 1]
>>> list(zeck(12))
[8, 3, 1]
>>> list(zeck(750))
[610, 89, 34, 13, 3, 1]

答案 4 :(得分:3)

已经证明,fib n的公式是fib(n) = ( (phi)^n - (-phi)^(-n) ) / sqrt(5),其中phi = (1+sqrt(5)) / 2是黄金分割数。 (见this link)。

你可以尝试找到上面的fib函数的数学逆,或者在32/64操作中进行二进制搜索(取决于你的可搜索最大值有多大)来找到与数字匹配的n(尝试每个n通过计算fib(n)并根据fib(n)与给定斐波那契数的比较将你的样本空间分成两部分。)

编辑:@ rcollyer的解决方案更快,因为我在O(lg n),他找到的是O(1)=恒定时间。

答案 5 :(得分:2)

所以我正在考虑这个问题,我认为可以在O(lg n)时间内使用O(lg n)内存使用。这是基于

的事实

F(n)=(1 /√5)(Φ n - φ n

其中Φ=(1 +√5)/ 2且φ= 1 - Φ。

第一个观察结果是φ n &lt; 1对于任何n>这意味着对于任何n> 1。 2,我们有那个

F(n)=⌊Φ n /√5⌋

现在,取n并以二进制形式写为b k-1 b k-2 ... b 1 b 0 。这意味着

n = 2 k-1 b k-1 + 2 k-2 b k-2 + ... + 2 1 b 1 + 2 0 b 0

这意味着

F(n)=⌊Φ 2 k-1 b k-1 + 2 k-2 b k-2 + ... + 2 1 b 1 + 2 0 b 0 /√5⌋

或者,更可读的是,

F(n)=⌊Φ 2 k-1 b k-1 Φ 2 k-2 b k-2 ...Φ 2 1 b 1 Φ< sup> 2 0 b 0 /√5⌋

这表明以下算法。首先,开始计算所有k的Φ 2 k ,直到计算出数Φ z ,使得⌊Φ z /√5⌋大于你的数字F(n)。现在,从那里开始,向后迭代你用这种方式生成的所有Φ的力量。如果当前数字大于Φ的指示功率,则将其除以Φ的功率,并记录该数字除以该值。这个过程实际上通过一次减去2的最大功率来一次恢复n位。因此,一旦你完成了,你就会找到n。

此算法的运行时间为O(lg n),因为您可以通过重复平方生成Φ 2 i ,并且我们只生成O(lg n)项。内存使用量为O(lg n),因为我们存储了所有这些值。

答案 6 :(得分:2)

你可以在O(1)时间和O(1)空间中找到任何Fib(n)的n。

您可以使用定点CORDIC算法仅使用shift计算ln()并添加整数数据类型。

如果x = Fib(n),那么n可以通过

确定
     n = int(2.0801 * ln(x) + 2.1408)

CORDIC运行时间由所需的精度级别决定。两个浮点值将被编码为定点值。

此提议的唯一问题是它返回不在Fibonacci序列中的数字的值,但原始问题明确指出函数的输入将是Fib(n),这意味着只有有效的Fibonacci数字将被使用。

答案 7 :(得分:1)

编辑:没关系。提问者在评论中指出取幂绝对不是恒定的时间。


取幂是指您在恒定时间内允许的数学运算之一吗?如果是这样,我们可以通过closed-form formula在恒定时间内计算F(n)。然后,给定一些F,我们可以做到以下几点:

  1. 计算F(1),F(2),F(4),F(16),F(256),...直到F(2 ^ k)&lt; = F&lt; F(2 ^ {K + 1})
  2. 在2 ^ k和2 ^ {k + 1}之间对i进行二分搜索,直到F(i)<= F <1。 F(I + 1)
  3. 如果F = F(n),则第一部分采用k = O(log(n))步。第二部分是在大小为O(2 ^ k)的范围内的二进制搜索,因此它也需要k = O(log(n))。所以,总的来说,我们在O(1)空间中有O(log(n))时间如果(并且它是一个很大的if)我们在O(1)时间内取幂。

答案 8 :(得分:1)

Fibonacci数公式的封闭形式是:

Fn = Round(φ^n / Sqrt(5))

其中φ是黄金比例。

如果我们忽略舍入因子,这是可逆的,反函数是:

F(-1)n= log(n*Sqrt(5))/logφ 

因为我们忽略了舍入因子,所以公式中存在可以计算的错误。但是,如果我们认为数n是斐波那契数,如果区间[n *φ - 1 / n,n *φ+ 1 / n]包含一个自然数,那么:

如果区间[n *φ - 1 / n,n *φ+ 1 / n]包含一个自然数,则该数字是斐波纳契数,并且斐波那契数列中的数字索引由舍入log(n * Sqrt)给出(5))/logφ

这应该在(伪) - 恒定时间内可行,这取决于用于计算对数和平方根等的算法。

编辑:φ=(1 + Sqrt(5))/ 2

答案 9 :(得分:1)

这可能类似于user635541的回答。我不完全理解他的做法。

使用其他答案中讨论的Fibonacci数字的矩阵表示,我们可以在恒定时间内从F_nF_mF_{n+m}F_{n-m},仅使用加号,乘法,减号和除法(实际上不是!请参阅更新)。我们也有一个零(单位矩阵),所以它是一个数学小组!

通常在进行二分查找时,我们还需要一个除法运算符来取平均值。或至少除以2.但是,如果我们想要从F_{2n}转到F_n,则需要一个平方根。幸运的是,事实证明加号和减号都是对数时间所需要的所有&#39;几乎&#39;二分搜索!

维基百科写了关于这种方法,具有讽刺意味的是Fibonacci_search,但文章写得不是很清楚,所以我不知道它是否与我的方法完全相同。了解用于斐波纳契搜索的斐波纳契数与我们正在寻找的数字无关,这一点非常重要。这有点让人困惑。为了演示这种方法,首先是标准二进制搜索&#39;的实现。只使用加号和减号:

def search0(test):
    # Standard binary search invariants:
    #   i <= lo then test(i)
    #   i >= hi then not test(i)
    # Extra invariants:
    #   hi - lo = b
    #   a, b = F_{k-1}, F_k
    a, b = 0, 1
    lo, hi = 0, 1
    while test(hi):
        a, b = b, a + b
        hi = b
    while b != 1:
        mi = lo + a
        if test(mi):
            lo = mi
            a, b = 2*a - b, b - a
        else:
            hi = mi
            a, b = b - a, a
    return lo

>>> search0(lambda n: n**2 <= 25)
5
>>> search0(lambda n: 2**n <= 256)
8

这里test是一些布尔函数; ab是连续的斐波纳契数f_kf_{k-1},因此上限hi和下限lo之间的差异始终为{ {1}}。我们需要f_ka,因此我们可以有效地增加和减少隐式变量b

好的,那么我们如何使用它来解决问题呢?我发现围绕我们的Fibonacci表示创建一个包装器很有用,它隐藏了矩阵细节。在实践中(斐波那契搜索者有这样的事情吗?)你想要手动内联一切。这样可以省去矩阵中的冗余,并围绕矩阵求逆进行一些优化。

k

但是代码确实有效,所以我们可以按如下方式测试它。注意当我们的对象是整数而不是Fibonaccis时,搜索函数的差别很小。

import numpy as np
class Fib:
    def __init__(self, k, M):
        """ `k` is the 'name' of the fib, e.g. k=6 for F_6=8.
             We need this to report our result in the very end.
            `M` is the matrix representation, that is
             [[F_{k+1}, F_k], [F_k, F_{k-1}]] """
        self.k = k
        self.M = M
    def __add__(self, other):
        return Fib(self.k + other.k, self.M.dot(other.M))
    def __sub__(self, other):
        return self + (-other)
    def __neg__(self):
        return Fib(-self.k, np.round(np.linalg.inv(self.M)).astype(int))
    def __eq__(self, other):
        return self.k == other.k
    def value(self):
        return self.M[0,1]

剩余未解决的问题是否存在针对幺半群的有效搜索算法。那是一个不需要减号/加法逆的算法。我的猜测是否定的:没有减去你就需要Nikita Rybak的额外记忆。

更新

我刚才意识到我们根本不需要分工。 def search(test): Z = Fib(0, np.array([[1,0],[0,1]])) # Our 0 element A = Fib(1, np.array([[1,1],[1,0]])) # Our 1 element a, b = Z, A lo, hi = Z, A while test(hi.value()): a, b = b, a + b hi = b while b != A: mi = lo + a if test(mi.value()): lo = mi a, b = a+a-b, b-a else: hi = mi a, b = b-a, a return lo.k >>> search(lambda n: n <= 144) 12 >>> search(lambda n: n <= 0) 0 矩阵的行列式只是F_n,因此我们实际上可以在没有除法的情况下完成所有事情。在下面我删除了所有的矩阵代码,但我保留了(-1)^n类,因为一切都变得非常混乱。

Fib

这一切都像一个魅力。我唯一担心的是,比特复杂性在计算中占主导地位,我们也可能刚刚进行了顺序搜索。或者实际上,只看数字位数可能会告诉你几乎你在看什么。但这并不是那么有趣。