走樓梯——走樓梯(一)

在介紹動態(tài)規(guī)劃的核心思想前撵孤,先看一道題槐雾。

LeetCode_70_ClimbingStairs

題目分析:

令dp[i]代表有多少種方法可到達第i層航厚,
由于第i層只能由i-1走一層或者i-2走兩層達到尝艘,
故可得dp[i] = dp[i-2] + dp[i-1]赴穗,
很明顯根據(jù)題意dp[1] = 1,dp[2] = 2椎侠。
dp[0]哪去了第租?為了我們寫起來好看,浪費掉了我纪。
如果喜歡你也可以用dp[0] = 1, dp[1] = 2,只是最后結(jié)果是dp[i-1]而不是dp[i]就是了慎宾。

解法一:遞歸

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

解法一分析

  解法一存在一個問題,
  因為dp[i] = dp[i-2] + dp[i-1]浅悉,則dp[i-1] = dp[i-3] + dp[i-2]趟据,
  此刻dp[i-2]重復(fù)出現(xiàn)了兩次。
  關(guān)鍵就在這里术健,這個重復(fù)的dp[i-2]并非重復(fù)一次這么簡單汹碱,
  因為dp[i-2]又是由dp[i-4]+dp[i-3]得到,層層遞歸下去苛坚,將是2^(i-2)次函數(shù)調(diào)用比被,
  舉一個例子,當(dāng)i=30時候泼舱,dp[i]將會調(diào)用函數(shù)1664079次等缀!

解法二:遞歸-動態(tài)規(guī)劃

public static int climbStairs_dp_recursion(int n, int[] dp){
    if(1 == n)
        return 1;
    else if(2 == n)
        return 2;
    if(0 == dp[n])
        dp[n] = climbStairs_dp_recursion(n-2, dp) + climbStairs_dp_recursion(n-1, dp);
    return dp[n];
}

解法二分析

  1.使用一個數(shù)組來緩存了中間結(jié)果,防止了“重疊子問題”的重復(fù)計算娇昙。

  2.解法二依然存在一個問題尺迂,就是在于“遞歸”這種寫法,遞歸產(chǎn)生的函數(shù)調(diào)用將消耗線程棧內(nèi)存冒掌。
    使用-Xss180k作為虛擬機啟動參數(shù)將線程棧設(shè)置為180k(jvm允許的最小值)噪裕,
    并將問題規(guī)模n設(shè)置為3000,就會出現(xiàn)Stack Over flow股毫。

解法三:循環(huán)-動態(tài)規(guī)劃

public static int climbStairs_dp_loop(int n){
    if(1 == n)
        return 1;
    else if(2 == n)
        return 2;

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

解法三分析

1.解決方法是改為循環(huán)膳音,
  因為遞歸和循環(huán)永遠可以相互轉(zhuǎn)換,請不要懷疑“永遠”這個詞的嚴謹性铃诬。

2.最后還有一個可優(yōu)化的點祭陷,內(nèi)存使用苍凛。
  我們使用dp[i] = dp[i-2] + dp[i-1]這個式子,循環(huán)遞推出結(jié)果兵志,
  dp[i]使我們想要的結(jié)果醇蝴,而只需要dp[i-2]和dp[i-1]得到,
  然而我們卻保留了i個也就是所有遞推過程的中間結(jié)果想罕,顯然這是一種浪費悠栓。

解法四:循環(huán)-動態(tài)規(guī)劃-內(nèi)存優(yōu)化

public static int climbStairs_dp_loop_lessMemory(int n){
    if(1 == n)
        return 1;
    else if(2 == n)
        return 2;

    int res = 0;
    int temp1 = 1;
    int temp2 = 2;
    for (int i = 3; i < n+1; i++) {
        res = temp1 + temp2;
        temp1 = temp2;
        temp2 = res;
    }
    return res;
}

解法四分析

通過兩個變量的交替更新使用,達到了節(jié)約內(nèi)存的目的按价,
這種不斷更新兩個變量的做法惭适,就像將整個數(shù)組“滾動”起來了一樣,在動態(tài)規(guī)劃中稱為“滾動數(shù)組”俘枫。
這里不用擔(dān)心我們丟掉的結(jié)果腥沽,因為題目只求最后的值。

總結(jié)

1.將結(jié)果集合之間的關(guān)系描述為“動態(tài)轉(zhuǎn)換方程”鸠蚪。
動態(tài)規(guī)劃的所有核心都在這一步今阳。
在做dp時,
不要關(guān)注數(shù)據(jù)和最終結(jié)果的關(guān)系茅信。
關(guān)注結(jié)果集合之間的關(guān)系盾舌!
結(jié)果集合指什么,此題中所有dp[i]的值的集合就是結(jié)果集合蘸鲸。
我們找到的dp[i] = dp[i-2] + dp[i-1]妖谴,就是結(jié)果集合之間的關(guān)系。
這個關(guān)系就是"動態(tài)轉(zhuǎn)換方程"酌摇。
2.構(gòu)造遞推初始項膝舅。
3.緩存推導(dǎo)過程中的“重疊子問題”,防止重復(fù)計算窑多。
4."滾動使用變量或數(shù)組"是常見的dp內(nèi)存優(yōu)化方式仍稀。

相應(yīng)例題的 Github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市埂息,隨后出現(xiàn)的幾起案子技潘,更是在濱河造成了極大的恐慌,老刑警劉巖千康,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件享幽,死亡現(xiàn)場離奇詭異,居然都是意外死亡拾弃,警方通過查閱死者的電腦和手機值桩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來豪椿,“玉大人奔坟,你說我怎么就攤上這事斯入。” “怎么了蛀蜜?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長增蹭。 經(jīng)常有香客問我滴某,道長,這世上最難降的妖魔是什么滋迈? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任霎奢,我火速辦了婚禮,結(jié)果婚禮上饼灿,老公的妹妹穿的比我還像新娘幕侠。我一直安慰自己,他們只是感情好碍彭,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布晤硕。 她就那樣靜靜地躺著,像睡著了一般庇忌。 火紅的嫁衣襯著肌膚如雪舞箍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天皆疹,我揣著相機與錄音疏橄,去河邊找鬼。 笑死略就,一個胖子當(dāng)著我的面吹牛捎迫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播表牢,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼窄绒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了初茶?” 一聲冷哼從身側(cè)響起颗祝,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恼布,沒想到半個月后螺戳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡折汞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年倔幼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爽待。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡损同,死狀恐怖翩腐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情膏燃,我是刑警寧澤茂卦,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站组哩,受9級特大地震影響等龙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伶贰,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一蛛砰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧黍衙,春花似錦泥畅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至方椎,卻和暖如春障癌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辩尊。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工涛浙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摄欲。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓轿亮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胸墙。 傳聞我的和親對象是個殘疾皇子我注,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

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

  • LeetCode 刷題隨手記 - 第一部分 前 256 題(非會員),僅算法題迟隅,的吐槽 https://leetc...
    蕾娜漢默閱讀 17,784評論 2 36
  • 在理解動態(tài)規(guī)劃但骨、BFS和DFS一文中,只是初步講解了一下動態(tài)規(guī)劃智袭,理解的并不到位奔缠,這里再加深理解一下。 本文主要參...
    小碧小琳閱讀 11,163評論 1 11
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗吼野。 張土汪:刷leetcod...
    土汪閱讀 12,745評論 0 33
  • 青春dj閱讀 309評論 0 0
  • 曉風(fēng)拂面校哎,十二月的冷月染霜。 回程的路上,一樹的柳葉涑涑的落闷哆,雪已經(jīng)下了兩周了腰奋,落在地上一層又一層,被旋轉(zhuǎn)的風(fēng)撩起...
    遙可及閱讀 403評論 0 1