每日算法——動態規劃之Fibonacci數列

Outline
Fibonacci數列問題
最優子結構和遞推表達式
Fib問題的各類變種
青蛙跳-臺階跳
硬幣找零問題(敬請期待)

一、Fibonacci數列

1.1 最優子結構和遞推表達式

在很多生活場景中,我們都會遇到求解F(n) = F(n-1) + F(n-2)這類問題。它是一類非常重要的經典的簡單的動態規劃問題。首先F(n)的解是由F(n-1)和F(n-2)組成,而F(n-1)的解是由F(n-1-1),F(n-1-2)組成,因此求解該類問題的過程就是不斷尋找F(n-x)的解的過程,因此F(n-x)都F(n)的子問題。具備子問題的問題都可以大化小,小化0與1,大大降低問題複雜度。簡單來說,我們把這種具備子問題的特徵叫做最優子結構性質。
找到子問題後,求解子問題,顯然這個問題中子問題最終會轉化爲F(1), F(0),規定F(0) = 1;F(1) = 1,因此子問題F(2)= 1+1可以輕鬆求解。獲取到子問題的解是不夠的,我們最終的目的是得到原問題的解,因此需要找到子問題和原問題之間的關係,在Fibonacci問題中輕鬆獲取兩者關係F(n) = F(n-1) + F(n-2)。我們把兩者的關係叫做遞推表達式。
有了子問題和遞推表達式,那麼求解原問題就迎刃而解了。
回到Fibonacci問題,注意到F(n-1) = F(n -2) + F(n-3) ,F(n-2)即用於求解F(n)也用於求解F(n-1)那麼我們將第一次求解F(n-2)獲取的值保存起來,那麼就不必重複計算,加快效率。因此我們將cumbersomeO(2^n)的算法改進爲O(n)的算法。

//cumbersome version
long long cumbFib(int n)
{
    if (n == 0)
    {
        return 1;
    }
    if (n == 1)
    {
        return 1;
    }
    return cumbFib(n-1) + cumbFib (n-2);
}
// advanced version
long long modFib(int n,vector<long long> memo)
{
    if (memo[n] != 0)
    {
        return memo[n];
    }
    memo[n] = modFib(n-1,memo) + modFib(n-2,memo);
    return memo[n];
}
// another advance version -非遞歸方法
long long modFib2(int n, vector<long long> memo)
{
    memo[1] = 1;
    memo[0] = 1;
    for(int i = 2 ; i <= n; i++)
    {
        memo[i] = memo [i-1] + memo [i-2];
    }
    return memo[n];
}

利用數組將每次計算得到的數據先保存起來,用空間換時間。然鵝實際上,我們還可以繼續優化。由於沒次計算只需要用到兩個舊數據,那麼我們直接用變量保存這兩個舊數據就ok啦。

long long smartFib(int n){
    long long pre = 1,ppre = 1,cur ;
    for (int i = 2;i <= n; i ++)
    {
        cur = pre + ppre;
        pre = ppre;
        ppre = cur;
    }
    return cur;
}

好啦,寫到這裏,我想應該不能再繼續優化了吧!(嗯哼,any question?)那麼接下來討論此類問題的具體應用場景。

1.2 具體應用

1.2.1 青蛙跳問題

在這裏插入圖片描述

這個題目是經典的Fibonacci數列問題,甚至沒有一點改動。值得注意的一點是Note:0 <= n <= 100,如果沒有取模,那就必須考慮大數越界問題了。測試發現,當n >=92 時,C++ 中8字節long int已經無法表示其結果啦。n>=95時,最大範圍的Unsigned long long也撲街了,C++數據類型範圍表如下表所示(參考C官網文件)。至於Python則不需要考慮,因爲python中整形數字的大小取決計算機的內存 ,暫且無需考慮大數越界問題。
在這裏插入圖片描述
在這裏插入圖片描述

Reference
https://en.cppreference.com/w/c/types/limits

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章