斐波那契数列两种解法

数列:1,1,2,3,5,8,13,21,34,55…….,被称为斐波那契数列。
斐波那契数列特点:第一、第二个数为1,从第三个数开始,该值等于其前面两个数之和。

本文主要解决计算第N个斐波那契数的值。

1. 递归

/**
 * 斐波那契数列
 * @param  [int] $n [数列第n个数,由0开始算]
 * @return [int]    [数列第n个数的值]
 */
function fB($n)
{
    if ($n == 0 || $n == 1) {
        return 1;
    }
    if ($n > 1) {
        return fB($n - 1) + fB($n - 2);
    }
}

递归法虽简单,但在递归时没有重复利用已经计算出来的子值,其时间复杂度较高。

2. 数组方式

/**
 * 斐波那契数列
 * @param  [int] $n [数列第n个数,由0开始算]
 * @return [int]    [数列第n个数的值]
 */
function fB($n)
{
    $arr = [1, 1];
    if ($n == 0 || $n == 1) {
        return 1;
    }
    if ($n > 1) {
        for ($i = 2; $i <= $n; $i++) {
            $arr[$i] = $arr[$i - 1] + $arr[$i - 2];
        }
        return $arr[$n];
    }
}

当n的值比较大时,法2中的$arr数组随之也较大,空间复杂度较高。

通过分析斐波那契数列我们知道,当n大于等于2时,其值只与其前面两个数的值有关,所以在只需求出第n个值的时候,我们没必要浪费空间去存储在n前2个数之前的值。

法2 优化如下:

/**
 * 斐波那契数列
 * @param  [int] $n [数列第n个数,由0开始算]
 * @return [int]    [数列第n个数的值]
 */
function fB($n)
{
    $arr = [1, 1];
    if ($n == 0 || $n == 1) {
        return 1;
    }
    if ($n > 1) {
        for ($i = 2; $i <= $n; $i++) {
            $temp = $arr[0] + $arr[1];
            $arr[0] = $arr[1];
            $arr[1] = $temp;
        }
        return $arr[1];
    }
}

$arr 数组只保存第n-1和第n个数的值。

拓展:当n比较大时,如何获得第n个斐波那契数的值?(该值超过了计算机整型数的存储范围)

解法思路如下:采用两个数组存储第n-1和第n个数的值,每个数组的每个元素只存储0-9之间数,拆分倒叙存储,如13的存储形式为:[3,1],对这两个数组进行对应位置相加,满十进一,即可得出第n个数的倒叙数组,代码如下:

/**
 * 斐波那契数列(支持大数值)
 * @param  [int] $n [数列第n个数,由0开始算]
 * @return [int]    [数列第n个数的值]
 */
function fB($n)
{
    $arr1 = [1];
    $arr2 = [1];
    if ($n == 0 || $n == 1) {
        return 1;
    }
    if ($n > 1) {
        for ($i = 2; $i <= $n; $i++) {
            $arr3 = [];
            $to = 0; // 进位
            $total1 = count($arr1);
            $total2 = count($arr2);
            for ($j = 0; $j < $total1; $j++) {
                $sum = $arr1[$j] + $arr2[$j] + $to;
                $arr3[$j] = $sum % 10;
                $to = (int)($sum / 10);
            }
            if ($to > 0) { // 进位
                $arr3[$j] = $to;
            }
            for (; $j < $total2; $j++) {
                $arr3[$j] = $arr2[$j] + $to;
                $to = 0;
            }
            $arr1 = $arr2;
            $arr2 = $arr3;
        }
        $total2 = count($arr2);
        $result = '';
        for ($i = 0; $i < $total2; $i++) {
            $result = $arr2[$i] . $result;
        }
        return $result;
    }
}
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值