给出p,q,r,a,b,c 问题是,如何找到该系列的第n个术语。f(0)= p
f(1)= q
f(2)= r
对于n> 2
f(n)= a f(n-1)+ b f(n-2)+ c * f(n-3)+ g(n)
其中g(n)= n * n *(n + 1)
请帮助我为此找到更好的解决方案。
我尝试使用递归解决此问题。但这会消耗大量内存。
答案 0 :(得分:2)
比递归更好的方法是memoization。您只需要知道f(n)的最后三个值即可。 伪代码的解决方案如下所示:
if n == 0:
return p
else if n == 1:
return q
else if n == 2:
return r
else:
f_n-3 = p
f_n-2 = q
f_n-1 = r
for i from 3 to n:
f_new = a * f_n-1 + b * f_n-2 + c * f_n-3 + g(n)
fn-1 = fn-2
fn-2 = fn-3
fn-3 = f_new
return f_new
这样,您无需递归调用该方法并将所有计算出的值保留在堆栈中,而只需在内存中保留4个变量即可。
这应该计算得更快,并使用更少的内存。
答案 1 :(得分:1)
问题在于,对于每次使用f
的{{1}}调用,都会导致对n > 2
的三个额外调用。例如,如果我们调用f
,则会得到以下调用:
f(5)
因此,我们打了一个电话- f(5)
- f(4)
- f(3)
- f(2)
- f(1)
- f(0)
- g(3)
- f(2)
- f(1)
- g(4)
- f(3)
- f(2)
- f(1)
- f(0)
- g(3)
- f(2)
- g(5)
,打了一个电话f(5)
,打了两个电话f(4)
,打了四个电话f(3)
,打了三个电话f(2)
,和两次致电f(1)
。
由于我们多次调用f(0)
,因此这意味着每次都将花费资源,尤其是因为f(3)
本身会进行额外的调用。
我们可以让Python存储函数调用的结果,并返回结果,例如使用lru_cache
[Python-doc]。这种技术称为记忆化:
f(3)
这将导致如下调用图:
from functools import lru_cache
def g(n):
return n * n * (n+1)
@lru_cache(maxsize=32)
def f(n):
if n <= 2:
return (p, q, r)[n]
else:
return a*f(n-1) + b*f(n-2) + c*f(n-3) + g(n)
因此,现在我们只计算一次- f(5)
- f(4)
- f(3)
- f(2)
- f(1)
- f(0)
- g(3)
- g(4)
- g(5)
,f(3)
会将其存储在缓存中,如果再次调用lru_cache
,我们将永远不会评估{{1} }本身,缓存将返回预先计算的值。
但是,由于我们每次调用f(3)
,f(3)
和f(n-1)
时,上面的内容可以进行优化,我们只需要存储最后三个值,并每次计算下一个值基于最后三个值,然后移动变量,例如:
f(n-2)