裴波那契數(shù)列(動態(tài)規(guī)劃)

寫在前

百度百科:斐波那契數(shù)列(Fibonacci sequence)彻亲,又稱黃金分割數(shù)列太雨,因數(shù)學家萊昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數(shù)列”镶奉,指的是這樣一個數(shù)列:0是鬼、1饥追、1、2、3揭厚、5却特、8、13筛圆、21裂明、34、……這個數(shù)列從第三項開始太援,每一項都等于前兩項之和闽晦。裴波那契數(shù)列最具有和諧之美的地方是,越往后提岔,相鄰兩項的比值會無限趨向于黃金比1:0.618


斐波納契螺旋線:
斐波納契螺旋線

在數(shù)學上仙蛉,斐波那契數(shù)列以如下被以遞推的方法定義:

通項公式:

在現(xiàn)代物理、準晶體結構碱蒙、化學等領域荠瘪,斐波納契數(shù)列都有直接的應用。詳情百度百科赛惩。

而動態(tài)規(guī)劃哀墓,就要有一個數(shù)組來記錄狀態(tài)!

1.斐波那契數(shù)(509-易)

題目描述:斐波那契數(shù)喷兼,通常用 F(n) 表示篮绰,形成的序列稱為 斐波那契數(shù)列 。該數(shù)列由 0 和 1 開始季惯,后面的每一項數(shù)字都是前面兩項數(shù)字的和吠各。也就是:

F(0) = 0,F(xiàn)(1) = 1
F(n) = F(n - 1) + F(n - 2)星瘾,其中 n > 1
給你 n ,請計算 F(n) 惧辈。

輸入:3
輸出:2
解釋:F(3) = F(2) + F(1) = 1 + 1 = 2

思路:本題題目描述已經(jīng)給出狀態(tài)轉移方程琳状,直接寫代碼,然后進行空間復雜度優(yōu)化盒齿。注意:初始值dp[0] = 0念逞。

代碼:動態(tài)規(guī)劃

public int fib(int n) {
    if (n == 0) return 0;
    int[] dp = new int[n + 1];
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i <= n; ++i) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

空間優(yōu)化:注意,先更新前一個變量边翁,避免覆蓋翎承。

public int fib(int n) {
    if (n == 0) return 0;
    int pre1 = 0, pre2 = 1;
    for (int i = 2; i <= n; ++i) {
        int cur = pre1 + pre2;
        pre1 = pre2;
        pre2 = cur;
    }
    return pre2;
}

2.爬樓梯(70-易)

題目描述:有 N 階樓梯,每次可以上一階或者兩階符匾,求有多少種上樓梯的方法叨咖。

示例

輸入: 2
輸出: 2
解釋: 有兩種方法可以爬到樓頂。
1.  1 階 + 1 階
2.  2 階

思路:本題先寫出暴力解法,然后改寫為動態(tài)規(guī)劃甸各,最后進行空間優(yōu)化垛贤,其中,dp[i]代表走到第i階樓梯的方法數(shù)趣倾。

代碼1:遞歸暴力求解:F(n) = F(n - 1) + F(n - 2) (n > 2)

public int climbStairs(int n) {
    if (n == 1) return 1;
    if (n == 2) return 2;
    return climbStairs(n - 1) + climbStairs(n - 2);
}

ps:Leetcode測試超時聘惦!

代碼2:動態(tài)規(guī)劃

public int climbStairs(int n) {
    if (n == 1) return 1;
    int[] dp = new int[n + 1];
    dp[1] = 1;
    dp[2] = 2;
    for (int i = 3; i <= n; ++i) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

空間優(yōu)化:O(1)

public int climbStairs(int n) {
    if (n == 1) return 1;
    int pre1 = 1, pre2 = 2;
    for (int i = 3; i <= n; ++i) {
        int cur = pre1 + pre2;
        pre1 = pre2;
        pre2 = cur;
    }
    return pre2;
}

劍指 Offer 10- II. 青蛙跳臺階問題

class Solution {
    public int numWays(int n) {
        // 注意判斷特例!H辶怠善绎!
        if (n == 0 || n == 1) {
            return 1;
        }
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;

        for (int i = 2; i <= n; i++) {
            dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007;
        }
        return dp[n];
    }

    public int numWays(int n) {
        // 空間壓縮
        if (n == 0 || n == 1) {
            return 1;
        }
        int pre = 1, cur = 1;

        for (int i = 2; i <= n; i++) {
            int tmp = (pre + cur) % 1000000007;
            pre = cur;
            cur = tmp;
        }
        return cur;
    }
}

3.最小花費爬樓梯(746-易)

題目描述:數(shù)組的每個下標作為一個階梯,第 i 個階梯對應著一個非負數(shù)的體力花費值 cost[i](下標從 0 開始)诫尽。支付相應的體力值禀酱。你可以爬一個階梯或者兩個階梯,求達到頂部的最小花費箱锐,在開始時比勉,你可以選擇從下標為 0 或 1 的元素作為初始階梯。驹止。

示例

輸入:cost = [10, 15, 20]
輸出:15
解釋:最低花費是從 cost[1] 開始浩聋,然后走兩步即可到階梯頂,一共花費 15 臊恋。

輸入:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 
輸出:6 
解釋:最低花費方式是從 cost[0] 開始衣洁,逐個經(jīng)過那些 1 ,跳過 cost[3] 抖仅,一共花費 6 坊夫。

思路dp[i]:到達第i個臺階所花費的最少體力。**由于題目要求每爬上一個樓梯都要支付對應的體力值撤卢,才能進行下一步环凿。并且上一步花費的體力值最小(走一步和兩步)放吩,注意:最后一步不需要花費智听。

  • 狀態(tài)轉移方程式:dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]

代碼:動態(tài)規(guī)劃

public int minCostClimbingStairs(int[] cost) {
    int n = cost.length;
    int[] dp = new int[n];
    dp[0] = cost[0];
    dp[1] = cost[1];
    for (int i = 2; i < n; ++i) {
        dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
    }
    // 最后一步不需要花費渡紫,取倒數(shù)第1步和倒數(shù)第2步的最小值
    return Math.min(dp[n - 1], dp[n - 2]);
}

空間優(yōu)化:O(1)

public int minCostClimbingStairs(int[] cost) {
    int n = cost.length;
    int pre1 = cost[0], pre2 = cost[1];
    for (int i = 2; i < n; ++i) {
        int cur = Math.min(pre1, pre2) + cost[i];
        pre1 = pre2;
        pre2 = cur;
    }
    return Math.min(pre1, pre2);
}

4.信件錯排(補充Leetcode-634)

題目描述:有 N 個 信 和 信封到推,它們被打亂,求錯誤裝信方式的數(shù)量惕澎。

思路:本題顯然是一個動態(tài)規(guī)劃問題莉测,定義dp數(shù)組存儲錯誤方式的數(shù)量,dp[i]表示有i封信唧喉,i個信箱錯誤方式捣卤。事實上忍抽,對于信件 i 來說,信箱 i 是它的“專屬信箱”腌零,每個信件都不能放入自己的專屬信箱梯找。

狀態(tài)轉移方程:對于第N封信而言,假設其裝在了第 K 個信箱中益涧,對于第 K 封信锈锤,有兩種情況:

(1)信件 K 裝在信箱 N 中

image.png

這時,已經(jīng)完成K和N兩個信封闲询,只關注剩下 N-2 對信件和信箱久免,有 dp[N-2] 種錯誤裝信方法;K 的取值范圍: 1~N-1 扭弧,因此共有 (N-1)*dp[N-2] 種錯誤裝信方法阎姥。

(2)信件 K 未被裝在信箱 N 中

image.png

假設每個信封都有自己的專屬信箱,N的專屬信箱為K鸽捻,那么可以認為K的專屬信箱為N呼巴。因為本情況下,信件 K 不能放入自己的專屬信箱 N 御蒲。所以可以理解成求 N-1 封信件和 N-1 個信箱(除去信件 N)之間的錯排數(shù)量問題衣赶。即求 dp[N-1]。同時厚满,K 的取值范圍: 1~N-1 府瞄,因此共有 (N-1)*dp[N-1] 種錯誤裝信方法。

  • 狀態(tài)轉移方程:dp[i] = (i-1)*dp[i-2] + (i-1)*dp[i-1]

代碼:動態(tài)規(guī)劃

public int MailMisalignment(int n){
    if(n == 0 || n == 1) return 0;
    int[] dp = new int[n];
    dp[0] = 0;
    dp[1] = 1;
    for(int i = 2; i < n; ++i){
        dp[i] = (i - 1) * (dp[i-2] + dp[i-1]);
    }
    return dp[n - 1];
}

5.母牛生產(chǎn)(程序員代碼面試指南-P181)

題目描述:假設農(nóng)場中成熟的母牛每年都會生 1 頭小母牛碘箍,并且永遠不會死遵馆。第一年有 1 只小母牛,從第二年開始丰榴,母牛開始生小母牛货邓。每只小母牛 3 年之后成熟又可以生小母牛。給定整數(shù) N四濒,求 N 年后牛的數(shù)量换况。

思路dp數(shù)組存儲每年成熟小母女的數(shù)量。因為只有成熟的母女才會繼續(xù)生產(chǎn)牛峻黍。例:1复隆,2拨匆,3姆涩,4,6 ... ... 即第N年后牛的數(shù)量等于第N - 1年牛的數(shù)量惭每,加上第N - 3年成熟小母牛下的小母牛(3年成熟)骨饿。

  • 狀態(tài)轉移方程:dp[i] = dp[i - 1] + dp[i - 3], n > 3

代碼:動態(tài)規(guī)劃

public int cow(int n) {
    if (i < 4) return n;
    int[] dp = new int[n + 1];
    // 起始條件
    for (int i = 0; i < 4; ++i) {
        dp[i] = i;
    }
    // 從第4年才滿足狀態(tài)轉移方程
    for (int i = 4; i <= n; ++i) {
        dp[i] = dp[i - 1] + dp[i - 3];
    }
    return dp[n];
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末亏栈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宏赘,更是在濱河造成了極大的恐慌绒北,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件察署,死亡現(xiàn)場離奇詭異闷游,居然都是意外死亡,警方通過查閱死者的電腦和手機贴汪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門脐往,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扳埂,你說我怎么就攤上這事业簿。” “怎么了阳懂?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵梅尤,是天一觀的道長。 經(jīng)常有香客問我岩调,道長巷燥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任誊辉,我火速辦了婚禮矾湃,結果婚禮上,老公的妹妹穿的比我還像新娘堕澄。我一直安慰自己邀跃,他們只是感情好,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布蛙紫。 她就那樣靜靜地躺著拍屑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坑傅。 梳的紋絲不亂的頭發(fā)上僵驰,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音唁毒,去河邊找鬼蒜茴。 笑死,一個胖子當著我的面吹牛浆西,可吹牛的內(nèi)容都是我干的粉私。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼近零,長吁一口氣:“原來是場噩夢啊……” “哼诺核!你這毒婦竟也來了抄肖?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤窖杀,失蹤者是張志新(化名)和其女友劉穎漓摩,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體入客,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡管毙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了桌硫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锅风。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畔柔,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布边器,位于F島的核電站,受9級特大地震影響托修,放射性物質發(fā)生泄漏忘巧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一睦刃、第九天 我趴在偏房一處隱蔽的房頂上張望砚嘴。 院中可真熱鬧,春花似錦涩拙、人聲如沸际长。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽工育。三九已至,卻和暖如春搓彻,著一層夾襖步出監(jiān)牢的瞬間如绸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工旭贬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怔接,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓稀轨,卻偏偏與公主長得像扼脐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子靶端,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容