1. 程式人生 > 實用技巧 >求斐波拉契數列第n位演算法優化

求斐波拉契數列第n位演算法優化

在面試題中經常遇到求斐波拉契數列值的問題,最常見演算法是使用遞迴的方式,本篇部落格介紹如何優化該演算法效能。

斐波拉契數列的特性是:n=(n-2)+(n-1)

首先使用遞迴的方式求斐波拉契數列第30位:

static void Main(string[] args)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    Console.WriteLine(Fun(30));
    sw.Stop();
    Console.WriteLine("總執行時間:" + sw.Elapsed);
    Console.WriteLine("測量例項得出的總執行時間(毫秒為單位):" + sw.ElapsedMilliseconds);
    Console.WriteLine("總執行時間(計時器刻度標識):" + sw.ElapsedTicks);
    Console.WriteLine("計時器是否執行:" + sw.IsRunning.ToString());
}

public static int Fun(int n)
{
    if (n == 1 || n == 2)
    {
        return 1;
    }
    return Fun(n - 2) + Fun(n - 1);
}

執行結果:

遞迴的方式致使 Fun() 方法被多次重複呼叫,此時的空間複雜度為 O(n),時間複雜度為 O(2ⁿ),n的值越大,時間複雜度也就越大。為避免Fun() 被多次重複呼叫,減小時間複雜度,我們可以用陣列來儲存計算出來的資料。

public static int Fun(int n)
{
    int[] array = new int[n];
    array[0] = 1;
    array[1] = 1;
    for (int i = 2; i < n; i++)
    {
        array[i] = array[i - 2] + array[i - 1];
    }
    return array[n - 1];
}

執行結果:

執行程式時間比遞迴方式的小,效率明顯提升,此時時間複雜度為 O(n),空間複雜度為 O(n),但是我們發現,在計算n的值時,我們只需最新的三個數,前面的數就不需要了,那麼我們可以定義三個常量來減少空間複雜度。

public static int Fun(int n)
{
    int first = 1;
    int second = 1;
    int third = 2;
    for (int i = 3; i <= n; i++)
    {
        third = first + second;
        first = second;
        second = third;
    }
    return third;
}

執行結果:

此時程式執行時間和上個方法相差無幾,但是此時的空間複雜度從 O(n) 變成了0,時間複雜度為 O(n),所以這種方式是非常高效的。