動(dòng)態(tài)規(guī)劃 (一)

爬樓梯問題

問題描述
現(xiàn)在總共有10層臺(tái)階磺樱,一只青蛙一次只能跳一階或兩階。問總共有多少種跳法婆咸?

??分析一波: 青蛙即將一步到達(dá)第10階前只有兩種情況竹捉,即:1.從第9階一階跳上去;2.從第8階兩階跳上去尚骄。如果用 F(n)表示青蛙跳到第n階所需要的步數(shù)块差,則有:

F(1) = 1 , 當(dāng) n = 1 時(shí)
F(2) = 2 , 當(dāng) n = 2 時(shí)
F(n) = F(n - 1) + F(n - 2),  當(dāng) n > 2 時(shí)

所以, 二話不說先來一發(fā)遞歸:

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

我將初始層數(shù)設(shè)置為40倔丈,總共耗時(shí)328毫秒憨闰。如果設(shè)置為100層...反正我沒等我電腦把結(jié)果跑完...執(zhí)行結(jié)果如下:


??都說遞歸慢...遞歸慢,遞歸為何慢需五?為啥還要使用遞歸呢鹉动?首先,為什么要是用遞歸警儒,這很容易去解釋训裆,因?yàn)樗Z句簡(jiǎn)潔、邏輯表達(dá)清晰蜀铲,寫出來更能讓人去理解边琉,一目了然。那為什么執(zhí)行地慢记劝?是因?yàn)槿绻f歸層數(shù)比較深变姨,需要增加額外的堆棧去處理,這樣很容易造成 堆棧溢出Q岢蟆定欧!對(duì)于遞歸的每一層,都需要堆棧去存儲(chǔ)調(diào)用參數(shù)和中間變量怒竿,所以會(huì)增加很多額外的系統(tǒng)開銷砍鸠。

??那有沒有辦法既能使代碼簡(jiǎn)潔,又能讓效率提升呢耕驰? 嗯確實(shí)是有的爷辱,可以采取一種叫做尾遞歸的方法。怎么去理解尾遞歸呢朦肘?我這里對(duì)其概念不做過多介紹饭弓,一句話總結(jié)什么是尾遞歸: 將當(dāng)前計(jì)算結(jié)果作為參數(shù)傳入下一層

改用尾遞歸的代碼如下:

/**
     * 
     * @param n
     * @param init1 初始值1
     * @param init2 初始值2
     * @return
     */
    public static int numsOfStairs(int n, int init1, int init2) {
        if (n == 1) {
            return init1;
        } else if (n > 1) {
            return numsOfStairs(n - 1, init2, init1 + init2);
        } else {
            return 0;
        }
    }

再貼上初始值設(shè)為40時(shí)的測(cè)試結(jié)果:

??執(zhí)行速度是不是快了不少媒抠?正常的遞歸需要一層層向下進(jìn)行遞歸弟断,然后再向上返回結(jié)果。而尾遞歸只需要向下進(jìn)行遞歸趴生,每一層遞歸時(shí)都進(jìn)行計(jì)算阀趴,最后再返回一次結(jié)果昏翰。 除此之外,尾遞歸以犧牲兩個(gè)額外空間的方式刘急,來減少了中間變量的存儲(chǔ)和返回矩父。這樣一來, 不僅效率大大提升排霉,同時(shí)也避免了內(nèi)存溢出窍株。

??那么懊蒸,接下來就進(jìn)入正題悔常,引入動(dòng)態(tài)規(guī)劃算法。使用動(dòng)態(tài)規(guī)劃算法旋讹,可以讓每個(gè)狀態(tài)都只計(jì)算一次瑰钮,將結(jié)果保存下來進(jìn)行下一次的計(jì)算冒滩,同時(shí)無需堆棧來保存遞歸現(xiàn)場(chǎng)。

動(dòng)態(tài)規(guī)劃算法

??動(dòng)態(tài)規(guī)劃算法是通過拆分問題浪谴,定義問題狀態(tài)和狀態(tài)之間的關(guān)系开睡,使得問題能夠以遞推或者分治的方式去解決。
??動(dòng)態(tài)規(guī)劃算法的基本思想與分治法類似苟耻,也是將待求解的問題分解為若干個(gè)子問題(階段)篇恒,按順序求解子階段,前一子問題的解凶杖,為后一子問題的求解提供了有用的信息胁艰。在求解任一子問題時(shí),列出各種可能的局部解智蝠,通過決策保留那些有可能達(dá)到最優(yōu)的局部解腾么,丟棄其他局部解。依次解決各子問題杈湾,最后一個(gè)子問題就是初始問題的解解虱。
??由于動(dòng)態(tài)規(guī)劃解決的問題多數(shù)有重疊子問題這個(gè)特點(diǎn),為減少重復(fù)計(jì)算漆撞,對(duì)每一個(gè)子問題只解一次殴泰,將其不同階段的不同狀態(tài)保存在一個(gè)二維數(shù)組中。(百度百科)

??因?yàn)槊恳淮味加?code>F(n) = F(n-1)+ F(n-2)叫挟,因此我們需要用兩個(gè)臨時(shí)變量來存儲(chǔ)中間結(jié)果艰匙。同樣是爬樓梯問題限煞,使用動(dòng)態(tài)規(guī)劃后的方案如下:

public static int numsOfStairs(int n) {
        int fn1 = 1, fn2 = 2; // 分別存儲(chǔ) f(n - 1) 和 f(n - 2)
        if (n < 3) {
            return n;
        } else if (n >= 3) {
            int sum = 0;
            for (int i = 3; i <= n; i++) {
                sum = fn1 + fn2;
                fn1 = fn2;
                fn2 = sum;
            }
            return sum;
        } else {
            return 0;
        }
    }
動(dòng)態(tài)規(guī)劃算法的適用條件:
  1. 最優(yōu)化原理(最優(yōu)子結(jié)構(gòu)性質(zhì)): 一個(gè)最優(yōu)策略的子策略是最優(yōu)的抹恳。一個(gè)問題滿足最優(yōu)化原理又稱其具有最優(yōu)子結(jié)構(gòu)性質(zhì)。
  2. 無后效性: 各階段的狀態(tài)都是對(duì)過去歷史的總結(jié)署驻,而只有現(xiàn)階段狀態(tài)能影響未來的決策奋献,其他之前的狀態(tài)都無法影響未來的決策健霹。
  3. 子問題的重疊性: 動(dòng)態(tài)規(guī)劃將原來具有指數(shù)級(jí)時(shí)間復(fù)雜度的搜索算法改進(jìn)成了具有多項(xiàng)式時(shí)間復(fù)雜度的算法。其中的關(guān)鍵在于解決冗余瓶蚂,這是動(dòng)態(tài)規(guī)劃算法的根本目的糖埋。動(dòng)態(tài)規(guī)劃實(shí)質(zhì)上是一種以空間換時(shí)間的技術(shù),它在實(shí)現(xiàn)的過程中窃这,不得不存儲(chǔ)產(chǎn)生過程中的各種狀態(tài)瞳别,所以它的空間復(fù)雜度要大于其它的算法。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末杭攻,一起剝皮案震驚了整個(gè)濱河市祟敛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌兆解,老刑警劉巖馆铁,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異锅睛,居然都是意外死亡埠巨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門现拒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辣垒,“玉大人,你說我怎么就攤上這事印蔬≌Ч梗” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵扛点,是天一觀的道長(zhǎng)哥遮。 經(jīng)常有香客問我,道長(zhǎng)陵究,這世上最難降的妖魔是什么眠饮? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮铜邮,結(jié)果婚禮上仪召,老公的妹妹穿的比我還像新娘。我一直安慰自己松蒜,他們只是感情好扔茅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秸苗,像睡著了一般召娜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惊楼,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天玖瘸,我揣著相機(jī)與錄音秸讹,去河邊找鬼。 笑死雅倒,一個(gè)胖子當(dāng)著我的面吹牛璃诀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔑匣,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼劣欢,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了裁良?” 一聲冷哼從身側(cè)響起氧秘,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎趴久,沒想到半個(gè)月后丸相,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彼棍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年灭忠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片座硕。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弛作,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出华匾,到底是詐尸還是另有隱情映琳,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布蜘拉,位于F島的核電站萨西,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏旭旭。R本人自食惡果不足惜谎脯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望持寄。 院中可真熱鬧源梭,春花似錦、人聲如沸稍味。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽模庐。三九已至烛愧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背屑彻。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顶吮,地道東北人社牲。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像悴了,于是被迫代替她去往敵國和親搏恤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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