有时在递归编程时,你会多次调用具有相同参数的函数,这是不必要的 .
着名的例子斐波那契数字:
index: 1,2,3,4,5,6...
Fibonacci number: 1,1,2,3,5,8...
function F(n) {
if (n < 3)
return 1
else
return F(n-1) + F(n-2)
}
我们运行F(5):
F(5) = F(4) + F(3)
= {F(3)+F(2)} + {F(2)+F(1)}
= {[F(2)+F(1)]+1} + {1+1}
= 1+1+1+1+1
所以我们称之为:1次F(4)2次F(3)3次F(2)2次F(1)
动态编程方法:如果多次调用具有相同参数的函数,请将结果保存到变量中,以便下次直接访问它 . 迭代方式:
if (n==1 || n==2)
return 1
else
f1=1, f2=1
for i=3 to n
f = f1 + f2
f1 = f2
f2 = f
我们再次打电话给F(5):
fibo1 = 1
fibo2 = 1
fibo3 = (fibo1 + fibo2) = 1 + 1 = 2
fibo4 = (fibo2 + fibo3) = 1 + 2 = 3
fibo5 = (fibo3 + fibo4) = 2 + 3 = 5
如您所见,只要您需要多次调用,您只需访问相应的变量即可获取值而不是重新计算它 .
顺便说一下,动态编程并不意味着将递归代码转换为迭代代码 . 如果需要递归代码,还可以将子结果保存到变量中 . 在这种情况下,该技术称为memoization . 对于我们的示例,它看起来像这样:
// declare and initialize a dictionary
var dict = new Dictionary();
for i=1 to n
dict[i] = -1
function F(n) {
if (n < 3)
return 1
else
{
if (dict[n] == -1)
dict[n] = F(n-1) + F(n-2)
return dict[n]
}
}
因此,与分而治之的关系是D&D算法依赖于递归 . 并且它们的某些版本具有“具有相同参数问题的多个函数调用” . 搜索需要DP以改善D&D算法的T(n)的示例的“矩阵链乘法”和“最长公共子序列” .