目录
1.普通的递归斐波那契数列
function fac($n){
if($n == 1 || $n == 2) return 1;
else return fac($n-2) + fac($n-1)
}
2.尾递归:在使用递归的情况下,不爆栈
普通的递归,运行栈会被函数的递归调用占满了
因此在要求使用递归的情况下,可以使用尾递归
每次调用函数时不生成新的运行栈,利用上一次的结果
/**
* $a充当收集器,收集上一次运行栈的返回值,之后栈空间会被回收
* $a和$b参与每次的计算
* $n是斐波那契数列执行的次数
*/
function fac1($a,$b,$n){
if($n>2) return fac1($a+$b,$a,$n-1);
return $a;
}
3.记忆化搜索:减少不必要的重复计算,自上而下
在原本的斐波那契递归中,总会像如下图一样递归到最后再返回结果
其中,例如 以5为例,3 往下的部分,就会被重复计算两次,2往下的部分会被重复计算3次
如果数据量大的情况下,记忆化搜索减少的计算量是十分可观的
用该方法可以大大优化斐波那契数列解决速度
class Solution{
private $memory = []; //记录当前数字是否已经求出解
public function fac($n){
if($n == 0) return 0;
if($n == 1) return 1;
if(empty($this->memory[$n])) //若没有对应的解,则继续进行递归
$this->memory[$n] = $this->fac($n-1) + $this->fac($n-2);
return $this->memory[$n]; //有解则直接返回该斐波那契数列
}
}
$q = new Solution();
echo $q->fac(40);
4.动态规划:自上而下,非递归
非递归,减少了系统栈的建立,比记忆化搜索还快
将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案
function fac($n){
if($n == 1 || $n == 2) return 1;
$a = 1;
$b = 1;
$res = 0;
for($i = 3;$i<=$n;++$i){
$res = $a + $b;
$a = $b;
$b = $res;
}
return $res;
}