斐波那契数列指的是 x 0 = 1 x_0=1 x0=1 x 1 = 1 x_1=1 x1=1 x n = x n − 1 + x n − 2 , n = 3 , 4 , 5 , . . . x_n=x_{n-1}+x_{n-2}, n=3,4,5,... xn=xn−1+xn−2,n=3,4,5,... 如果果要计算 f(10),需要先计算出 f(8) 和 f(9),然后就能由 f(8)+f(9) 计算得到 f(10) 了。
def feibonaci(n): if n == 1: return 1 if n == 2: return 1 return feibonaci(n-1) + feibonaci(n-2) print(feibonaci(30))递归代码有计算效率的问题。计算 f(10) 的时候,需要先计算 f(8) 和 f(9),为了计算 f(9),还必须计算 f(7) 和 f(8),显然,计算了两遍 f(8)。类似地,为了计算 f(7) 和 f(8),又得多次计算 f(6)。为了提高计算效率,可以采用备忘录算法,在第一次计算出 f(6) 时,将它存储起来,当需要再次计算 f(6),以查表来替代计算,来换取更高的效率。
hs = {} def feibonaci(n): if n == 1: return 1 if n == 2: return 1 if n in hs: return hs[n] res = feibonaci(n-1) + feibonaci(n-2) hs[n] = res return res print(feibonaci(30))为递归添上了备忘录,距离动态规划还有一步之遥。毕竟,用hs存储历史信息要花费不小的空间,能不能缩减所要的空间?就计算过程来看,hs[1]只用于计算 f(2) 和 f(3),而与计算 f(4)、f(5)等无关。所以,调整一下计算顺序,按照 n 从小到大的顺序来计算 f(n),就能减少hs占用的空间。
def feibonaci(n): if n == 1: return 1 if n == 2: return 1 hs1 = 1 hs2 = 1 for i in range(3, n): hs1, hs2 = hs2, hs1 + hs2 return hs1 + hs2 print(feibonaci(30))当然,不是所有的问题都能如此简化,但是消除递归依旧能提高运行效率。 总结下,动态规划就是大事化小,小事化了,用查表替代计算,改变顺序消除递归。