如何在Python或Java中加快此递归函数的速度?

如何在Python或Java中加快此递归函数的速度?,java,python,recursion,Java,Python,Recursion,我有一个递归函数: F(n)=4F(n-1)+F(n-2),对于所有n>=2,其中F(0)=0,F(1)=1。 这是我用python编写的代码 def f(n): res = 0; if n == 0: return 0 elif n == 1: return 1 else: res=(4*(f(n-1)))+f(n-2) return res print f(2424) 以及Java中

我有一个递归函数: F(n)=4F(n-1)+F(n-2),对于所有n>=2,其中F(0)=0,F(1)=1。 这是我用python编写的代码

def f(n):
    res = 0;
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        res=(4*(f(n-1)))+f(n-2)        
    return res


print f(2424)
以及Java中的方法:

static public long f(int n){
    long res = 0;
    if(n==0){
        return 0;
    }else if(n==1){
        return 1;
    }else{
    res=(4*(f(n-1)))+f(n-2);
    }
    return res;
}
我只是简单地说:

public static void main(String[] args) {
    System.out.println("Answer "+f(2424));
}
我必须对F(2424)进行评估,但它花费的时间太长,以至于5小时后程序还没有完成。我想知道我是否做错了什么,或者是否有更好的方法来做到这一点。我对C、C++或Mathematica等其他语言开放。我知道它是有效的,因为对于较小的数字,它给出了正确的答案。F(2424)的答案是一个非常大的数字,它是这样的:

128116451111887631525475128340040975438337021032465443606249421545402287913406421734920886901057125688465422144704470288714758990921153496166236437695935555697103801778677462085188924098182725088076022685760387219787300753893097810064552580355667757575457147474758990921535153919191919445946399622103748654220284857434768723811900368455930677215054848996416691934717414352030770878189655349708272370088617205463337763986915180942063012994307233629605426555925124836050521444499111474463839727615711808324774260599874109224986225992338904160018276592442460182526613176681765888761915244766444582781801759075955640895784640535412898896583530854495953456381149562778943774402658091873287466207009296604036070639562647289572000261822425465089043313656573939569536654054677090750218737467173010688447428126408048983584503411470060709922311143096204137977283053639448572312486337772156811780487145559605832857694232695773470923184525979593764429848985978060868806656421714523588395850662909318298227582307310778309451672655308099393781174736252795563172674626472496404368906252690885792371150767839340277951873888326065507086594354815364434422367588907402904674764237367625964288589301685399188903414260498913741236024869107419652068886192177498984764598912039234195620225138711128495902102618736425015029002520928558368156722620208600383231181003567866386308880435236412040943537550104070196883278855174007270257961020139833244667655843894415660856081125569457906971646832


或者这只是一个我不得不等待的非常繁重的程序?

你可以使用O(logn)的矩阵求幂法

这里有一个链接解释它以及如何实现它


您可以对O(logn)使用矩阵求幂法

这里有一个链接解释它以及如何实现它


让我们看一个例子
n==5
,它将调用
f(4)
f(3)
。依次调用
f(3)
f(2)
f(2)
f(1)
。正如您所看到的,有很多多余的求值,当您转到更大的
n
时,会出现雪球

因此,只要跟踪您已经计算的内容,事情就会大大加快:

def f(n):
    res = 0;
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        res=(4*(f(n-1)))+f(n-2)        
    return res

def f_all(n):
    res = (n+1)*[0]
    res[1] = 1
    for i in range(2, n+1):
        res[i] = 4*res[i-1] + res[i-2]
    return res

print f(10) == f_all(10)[-1]
print f_all(2424)[-1]
更新:忍不住添加了高科技解决方案。它使用数学势利者所称的环Z[sqrt(5)]的矩阵表示来评估封闭形式的解决方案。这是必要的,因为如果n很大,浮点值就不够精确

def f_high_tech(n):
    import numpy as np
    powpow2_p = np.array([[2, 1], [5, 2]], dtype=object)
    power_p_n = np.identity(2, dtype=object)
    while n > 0:
        if n&1:
            power_p_n = np.dot(power_p_n, powpow2_p)
        powpow2_p = np.dot(powpow2_p, powpow2_p)
        n >>= 1
    return power_p_n[0, 1]

print f(10) == f_all(10)[-1]
print f_all(2424)[-1] == f_high_tech(2424) 
print f_high_tech(1<<20).bit_length()
def f_高科技(n):
将numpy作为np导入
POW2_p=np.array([[2,1],[5,2]],dtype=object)
power\u p\u n=np.identity(2,dtype=object)
当n>0时:
如果n&1:
power\u p\u n=np.dot(power\u p\n,pow2\u p)
POW2_p=np.dot(POW2_p,POW2_p)
n>>=1
返回功率p_n[0,1]
打印f(10)=f_全部(10)[-1]
打印f_all(2424)[-1]==f_high_tech(2424)

打印f_high_tech(1让我们看一个例子
n==5
,它将调用
f(4)
f(3)
。依次调用
f(3)
f(2)
f(2)
f(1)
。正如您所看到的,有很多多余的计算,当您转到更大的
n
时,会出现雪球

因此,只要跟踪您已经计算的内容,事情就会大大加快:

def f(n):
    res = 0;
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        res=(4*(f(n-1)))+f(n-2)        
    return res

def f_all(n):
    res = (n+1)*[0]
    res[1] = 1
    for i in range(2, n+1):
        res[i] = 4*res[i-1] + res[i-2]
    return res

print f(10) == f_all(10)[-1]
print f_all(2424)[-1]
更新:忍不住添加高科技解决方案。它使用数学势利者称之为环的矩阵表示来评估封闭形式的解决方案。这是必要的,因为如果n很大,浮点值就不够精确

def f_high_tech(n):
    import numpy as np
    powpow2_p = np.array([[2, 1], [5, 2]], dtype=object)
    power_p_n = np.identity(2, dtype=object)
    while n > 0:
        if n&1:
            power_p_n = np.dot(power_p_n, powpow2_p)
        powpow2_p = np.dot(powpow2_p, powpow2_p)
        n >>= 1
    return power_p_n[0, 1]

print f(10) == f_all(10)[-1]
print f_all(2424)[-1] == f_high_tech(2424) 
print f_high_tech(1<<20).bit_length()
def f_高科技(n):
将numpy作为np导入
POW2_p=np.array([[2,1],[5,2]],dtype=object)
power\u p\u n=np.identity(2,dtype=object)
当n>0时:
如果n&1:
power\u p\u n=np.dot(power\u p\n,pow2\u p)
POW2_p=np.dot(POW2_p,POW2_p)
n>>=1
返回功率p_n[0,1]
打印f(10)=f_全部(10)[-1]
打印f_all(2424)[-1]==f_high_tech(2424)

打印f_high_tech(1让我们通过递归关系的精确值进行检查

 F(n)=4F(n-1)+F(n-2) = 1/10*(2+sqrt(5))^n*sqrt(5)-1/10*(2-sqrt(5))^n*sqrt(5) 
F(10)=416020.0

这是一个非常核心的循环,运行时间非常长。看看这个图:


计算F(2424)真的需要很长时间。

让我们通过递归关系的精确值来检查

 F(n)=4F(n-1)+F(n-2) = 1/10*(2+sqrt(5))^n*sqrt(5)-1/10*(2-sqrt(5))^n*sqrt(5) 
F(10)=416020.0

这是一个非常核心的循环,运行时间非常长。看看这个图:


计算F(2424)真的需要很长时间

使用高级表示语言,您真的无法再做任何事情了。如果您真的想获得尽可能最好的优化,您将需要进行汇编。但一旦达到该级别,您将意识到不会有太多变化。为什么?请看代码。没有太多需要优化的内容。如果您使用C,您可能会发现具有我会给你一个很好的可执行文件,但出于下面所述的原因,这并不重要

你的斐波那契问题

您当前的问题有一个解决方案。此解决方案取决于输入和您解决问题的方式。现在查看您的算法,您正在处理解决问题的指数时间复杂性:O(2^n)。这意味着小输入将提供