1. 程式人生 > >斐波那契數列兩種解法

斐波那契數列兩種解法

數列: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;
    }
}