2个斐波纳契数的乘积

时间:2017-08-16 22:04:27

标签: python python-3.x function fibonacci

我的任务:

  

给出一个数字,比如prod(对于产品),我们搜索两个Fibonacci   数字F(n)和F(n + 1)验证

F(n) * F(n+1) = prod if F(n) * F(n+1) = prod
     

你的函数productFib取一个整数(prod)并返回一个数组:

[F(n), F(n+1), True] else 
      F(m)是最小的,例如F(m)* F(m + 1)>刺

[F(m), F(m+1), False] 
     

示例:

productFib(714) # should return [21, 34, True], 
            # since F(8) = 21, F(9) = 34 and 714 = 21 * 34

productFib(800) # should return [34, 55, False], 
            # since F(8) = 21, F(9) = 34, F(10) = 55 and 21 * 34 < 800 < 34 * 55

我的代码:

def f(i):
    if i == 0 :
        return 0
    if i == 1 :
        return 1
    return f(i-2) + f(i-1)

def productFib(prod):
    i=1
    final1 = 0
    final2 = 0
    while(f(i)*f(i+1) != prod and f(i)*f(i+1) < prod):
        i += 1
        final1 = f(i)
        final2 = f(i+1)
    if(final1*final2 == prod):
        return [final1,final2,True]
    else:
        return [final1,final2,False]

我是编程新手;这对于大数字来说非常慢。如何减少时间复杂度?

7 个答案:

答案 0 :(得分:4)

首先,您的 f 功能非常耗时:它会多次计算 f(n)的低 n Memoize 该函数:将结果保存在列表中,并在再次计算时引用该列表。

root5 = 5 ** 0.5
phi = (1 + root5) / 2
psi = (1 - root5) / 2

def f(i):
    return int(round((phi ** i - psi ** i) / root5))

请注意,此序列仍然保证您将按数字顺序填写备忘录:在f(i-1)之前调用f(i-2),并且在添加f之前调用它们( i)到列表中。

使用此方法调用 f(100000000000000)(10 ^ 14)即时返回。我没有尝试过更高的数字。

<强>更新

我以10的增加速度运行它。在10 ^ 1650时,它仍然以全速打印输出,我打断了运行。

<强>改进

您可以通过直接从封闭形式的等式中计算 f(i)来做得更好(对于许多应用程序):

f(i) * f(i+1)

更多改进

直接计算 i 的正确值。 phi**(2i+1) / 5非常接近def productFib(prod): power = math.log(prod*5) / log_phi i = int(round(power-1, 7)/2) + 1 low = f(i) high = f(i+1) # print i, low, high answer = [low, high, low*high == prod] return answer print productFib(714) print productFib(800) print productFib(100000000000000000)

[21, 34, True]
[34, 55, False]
[267914296, 433494437, False]

输出:

{{1}}

答案 1 :(得分:4)

print((lambda prod: (lambda n: next(([a, b, (a * b) == prod] for a, b in ([n.append(n[0] + n[1]), n.pop(0), n][-1] for _ in iter(int, 1)) if (a * b) >= prod)))([0, 1]))(714))

答案 2 :(得分:2)

您可以通过使用生成器来提高性能。

SET SESSION storage_engine = "InnoDB";
SET SESSION time_zone = "+0:00";
ALTER DATABASE CHARACTER SET "utf8";

DROP TABLE IF EXISTS entries;
CREATE TABLE entries (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
author_id INT NOT NULL REFERENCES authors(id),
slug VARCHAR(100) NOT NULL UNIQUE,
title VARCHAR(512) NOT NULL,
markdown MEDIUMTEXT NOT NULL,
html MEDIUMTEXT NOT NULL,
published DATETIME NOT NULL,
updated TIMESTAMP NOT NULL,
KEY (published)
);

DROP TABLE IF EXISTS authors;
CREATE TABLE authors (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(100) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
hashed_password VARCHAR(100) NOT NULL
);

这是

的输出
def fib():
    # Generator that yields the last two fibonacci numbers on each iteration.
    # Initialize
    np = 0
    n = 1

    # Loop forever. The main function will break the loop.
    while True:
        # Calculate the next number
        nn = np + n

        # Yield the previous number and the new one.
        yield n, nn

        # Update the generator state.
        np = n
        n = nn

def product_fib(prod):
    # Loop through the generator.
    for f_0, f_1 in fib():
        # If the product is larger or equal to the product return.
        if f_0 * f_1 >= prod:
            # The last element in the list is the resut of the equality check.
            return [f_0, f_1, f_0 * f_1 == prod]


t0 = perf_counter()
res = productFib(8000000000)
t = perf_counter() - t0
print("Original:", t, res)

t0 = perf_counter()
res = product_fib(8000000000)  # 8000000000
t = perf_counter() - t0
print("New:", t, res)

修改

如果你想要一条线。它有效,但不能使用它,它不是最实用的解决方案。无论如何,第一个更快。

Original: 0.8113621789962053 [75025, 121393, False]
New: 1.3276992831379175e-05 [75025, 121393, False]

答案 3 :(得分:1)

您的dict = {} def f(i): if dict.has_key(i): return dict[i] if i == 0 : return 0 if i == 1 : return 1 sum = f(i-2) + f(i-1) dict[i] = sum return sum def productFib(prod): i=1 final1 = 0 final2 = 0 while(f(i)*f(i+1) != prod and f(i)*f(i+1) < prod): i += 1 final1 = f(i) final2 = f(i+1) if(final1*final2 == prod): return [final1,final2,True] else: return [final1,final2,False] 功能每次都会从底部重新计算。你应该保存你已经知道的价值。我的python生锈了,但我认为这样做了:

memo = [1, 1]

def f(i):
    global memo

    if i >= len(memo):
        # Compute all f(k) where k < i
        f_of_i = f(i-2) + f(i-1)
        memo.append(f_of_i)

    return memo[i]

答案 4 :(得分:0)

您可以将以下代码用于ProductFib功能

def productFib2(prod):
    i=0
    final1 = f(i)
    final2 = f(i+1)
    while(final1 * final2 < prod):
        i += 1
        final1 = final2
        final2 = f(i+1)
    if(final1*final2 == prod):
        return [final1,final2,True]
    else:
        return [final1,final2,False]

答案 5 :(得分:0)

以下是一些日益优化的不同算法(从原始算法开始)。

算法3 使用迭代斐波那契缓存以及猜测平方根(应该在斐波那契产品的两个倍数之间) )。

时间安排结果:

Original algorithm:                          4.43634369118898
Algorithm 2 (recursive fib):                 1.5160450420565503
Algorithm 2 (iter fib):                      0.03543769357344395
Algorithm 2 (iter fib + caching):            0.013537414072276377
Algorithm 3 (iter fib + caching + guessing): 0.0017255337946799898

<强>设定:

import timeit

from random import randint
from math import sqrt
from bisect import bisect

cache = [0, 1]

第N个Fibonacci数字算法:

def f(n):
    """Recursive solution: O(2^n)"""
    if n == 0:
        return 0
    if n == 1:
        return 1
    return f(n-2) + f(n-1)


def ff(n):
    """Iterative solution: O(n)"""
    a, b = 0, 1
    for _ in range(0, n):
        a, b = b, a + b
    return a


def fff(n):
    """Iterative solution + caching"""
    length = len(cache)
    if n >= length:
        for i in range(length, n+1):
            cache.append(cache[i-1] + cache[i-2])
    return cache[n]

Fibonacci产品算法:

def pf1(prod):
    """Original algorithm."""
    i=1
    final1 = 0
    final2 = 0
    while(f(i)*f(i+1) != prod and f(i)*f(i+1) < prod):
        i += 1
        final1 = f(i)
        final2 = f(i+1)
    if(final1*final2 == prod):
        return [final1,final2,True]
    else:
        return [final1,final2,False]


def pf2(prod, fib_func):
    """Algorithm 2.

    Removes extra logic and duplicate function calls."""
    i = 1
    guess = 0
    while guess < prod:
        final1 = fib_func(i)
        final2 = fib_func(i + 1)
        guess = final1 * final2
        i += 1

    return [final1, final2, guess == prod]


def pf3(prod, fib_func):
    """Algorithm 3.

    Implements square root as a guess."""
    guess = sqrt(prod)  # Numbers will be near square root

    i = 2
    while cache[-1] < guess:
        fff(i)
        i += 1

    insertion_spot = bisect(cache, guess)
    test1 = cache[insertion_spot-1]
    test2 = cache[insertion_spot]

    return [test1, test2, (test1 * test2) == prod]

测试&amp;输出:

prods = [randint(3, 99999) for _ in range(1000)]  # 1000 random products
print("Original algorithm:                         ", timeit.timeit("for prod in prods: pf1(prod)", number=1, setup="from __main__ import pf1, prods"))
print("Algorithm 2 (recursive fib):                ", timeit.timeit("for prod in prods: pf2(prod, f)", number=1, setup="from __main__ import pf2, prods, f"))
print("Algorithm 2 (iter fib):                     ", timeit.timeit("for prod in prods: pf2(prod, ff)", number=1, setup="from __main__ import pf2, prods, ff"))
print("Algorithm 2 (iter fib + caching):           ", timeit.timeit("for prod in prods: pf2(prod, fff)", number=1, setup="from __main__ import pf2, prods, fff"))
print("Algorithm 3 (iter fib + caching + guessing):", timeit.timeit("for prod in prods: pf3(prod, fff)", number=1, setup="from __main__ import pf3, prods, fff, cache; cache = [0, 1]"))

Python“列表”对象的有用时间复杂性: https://wiki.python.org/moin/TimeComplexity

答案 6 :(得分:0)

两种方式:慢速和快速方式

慢:

def productFib(prod):
    i=0
    final1 = f(i)
    final2 = f(i+1)
    while(final1 * final2 < prod):
        i += 1
        final1 = final2 #this is the same as final1 = f(i) again but, the value is already in memory no need to recalc it
        final2 = f(i+1)
    if(final1*final2 == prod):
        return [final1,final2,True]
    else:
        return [final1,final2,False] #if non equivilant product
def f(i): #fib(0) == 0 fib(1) == 1
    if i == 0 :
        return 0
    if i == 1 :
        return 1
    return f(i-2) + f(i-1)
while循环中产品的

输出: 0 1个 2 6 15

快速:

def productFib(prod):
    a, b = 0, 1
    while prod > a * b:

 1. List item

        a, b = b, a + b #a is equal to b and b is equal to the sum of a and b
    return [a, b, prod == a * b] #return a and b as well as the conditional if a times b is equal to the product

这里不需要检查是否属于fib系列,因为我们可以简单地在while循环内迭代该系列,而不必递归调用另一个函数 fib函数定义为:F(n)= F(n-1)+ F(n-2),其中F(0)= 0且F(1)=1。因此,可以使用以下算法生成该函数上面的while循环 随后a = 0,b = 1接下来a = 1,b = 1接下来a = 1,b = 2接下来a = 2,b = 3 接下来a = 3,b = 5 ...