<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          我的第437篇原創(chuàng):動(dòng)態(tài)規(guī)劃算法入門篇,真正幫助你入門?。?!

          共 3800字,需瀏覽 8分鐘

           ·

          2020-11-22 19:50

          Python與算法社區(qū)
          437篇原創(chuàng),干貨滿滿
          值得星標(biāo)


          01

          02

          03


          三步加星標(biāo)







          讀者朋友們好,我是 zhenguo


          今天這篇文章我構(gòu)思很久,也寫了很久,全文3330字,21張圖。如果可以的話,希望文末能點(diǎn)贊支持下,謝謝。


          本文目標(biāo)幫助朋友們認(rèn)識(shí)到動(dòng)態(tài)規(guī)劃算法之美,從而引發(fā)學(xué)習(xí)它、研究它的興趣。


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


          某個(gè)問題一旦找到動(dòng)態(tài)規(guī)劃的解法,一般便是接近或就是最優(yōu)解法,也正因?yàn)榇?,無數(shù)程序員為它著迷,大廠面試也是必考。


          但是,動(dòng)態(tài)規(guī)劃又非常靈活,本質(zhì)上沒有套路,問題不同,動(dòng)態(tài)規(guī)劃的迭代方程就不同。而有些問題,對于計(jì)算機(jī)科學(xué)家,都難以找到迭代方程。因此,對于平平常常的我們,刷算法題時(shí)想不出動(dòng)態(tài)規(guī)劃的解法,也大可不必氣餒。


          雖然它很難,但卻對訓(xùn)練我們的算法思維,很有幫助!并且持續(xù)的練習(xí)、總結(jié),也會(huì)為我們?nèi)蘸笞龀绦騼?yōu)化、性能提升、算法優(yōu)化相關(guān)工作,打下最為堅(jiān)實(shí)的基礎(chǔ)。


          一成不變、日復(fù)一日的重復(fù),難免讓人感到厭煩,如果添加一些靈活多變的成分,生活便會(huì)變得有意思起來。不斷追尋、不斷靠近目標(biāo)的日子,才更有意義!



          二 窮舉解法


          下面結(jié)合一道經(jīng)典的題目:最大子數(shù)組的和,對比暴力枚舉解法和動(dòng)態(tài)規(guī)劃解法,進(jìn)而體會(huì)動(dòng)態(tài)規(guī)劃的魅力。


          給定一個(gè)整數(shù)數(shù)組 nums ,找到一個(gè)具有最大和的連續(xù)子數(shù)組(子數(shù)組最少包含一個(gè)元素),返回其最大和。


          示例:


          輸入: [-2,1,-3,4,-1,2,1,-5,4]

          輸出: 6

          解釋: 連續(xù)子數(shù)組 [4,-1,2,1] 的和最大,為 6。


          就此題而言,原問題是??[-2,1,-3,4,-1,2,1,-5,4] ,


          子問題如?[-2],[1,-3],[-2,1,-3],[4,-1,2,-5],相應(yīng)的最大和為:-2,1,1,4,


          它們都是可行解,但不是最優(yōu)解。一共可能的子序列有:n + n*(n-1) / 2 ,對于數(shù)組長度為n的問題,暴力求解的時(shí)間復(fù)雜度為:O(n^2),即窮舉所有子序列,找出最大和。



          三?初識(shí)動(dòng)態(tài)規(guī)劃


          動(dòng)態(tài)規(guī)劃的基本思想通俗來說,要想求原問題的最優(yōu)解,只需要求得子問題的最優(yōu)解,組合子問題最優(yōu)解,進(jìn)而得到原問題的最優(yōu)解。


          某個(gè)問題是否能應(yīng)用動(dòng)態(tài)規(guī)劃,通常需要滿足3個(gè)條件:


          1. 最優(yōu)子結(jié)構(gòu)

          2. 后續(xù)狀態(tài)無關(guān)性

          3. 重復(fù)子問題


          這些太理論了,尤其初次接觸動(dòng)態(tài)規(guī)劃,看到這些會(huì)很懵。接下來,我會(huì)通過實(shí)例,進(jìn)一步形象化解釋這三個(gè)條件。?


          如果確認(rèn)問題滿足這三個(gè)條件后,下一步就是去尋找狀態(tài)相關(guān)的決策或策略,此策略如果能在原問題上求得最優(yōu)解,必然也能使用此策略,求得子問題的最優(yōu)解。如果不成立,表明策略是失敗的。


          下面先來判斷,這個(gè)問題適不適合動(dòng)態(tài)規(guī)劃求解。



          四 最優(yōu)子結(jié)構(gòu)


          下面是原問題:



          為了求得最優(yōu)解,能不能先求解下面藍(lán)色區(qū)域表示的子序列的最優(yōu)解?


          如果藍(lán)色色塊的最大和是如下紫色連續(xù)區(qū)域:


          那么,考慮上最后一個(gè)色塊4后,同時(shí)比較:包括-5元素在內(nèi)的最大和如果大于紫色色塊的和,那么最大和包括色塊4,否則不會(huì)包括色塊4,就是原來的紫色色塊 :




          所以只需求得子問題的最優(yōu)解后,原問題的最優(yōu)解便能推導(dǎo)出來,這表明此問題具備最有子結(jié)構(gòu)性質(zhì)!



          五?后續(xù)狀態(tài)無關(guān)性


          能夠應(yīng)用動(dòng)態(tài)規(guī)劃算法的另一個(gè)前提:后續(xù)狀態(tài)無關(guān)性,這個(gè)問題很明顯,如下藍(lán)色色塊區(qū)域,子數(shù)組的最大和,與后面的紅色色塊無關(guān):


          因此,子序列的最大和問題,具備后續(xù)狀態(tài)無關(guān)性。



          六 重復(fù)子問題


          如下是以-2為根節(jié)點(diǎn)的,可能連續(xù)搜索子路徑:



          如下是以1為根節(jié)點(diǎn),可能的連續(xù)搜索子路徑:



          任意選取一條以-2為根的子路徑:[-2, 1,-3,4],和以1為根的子路徑[1,-3,4],求出子路徑[-2, 1,-3,4]的連續(xù)最大和,后面又去求解子問題[1,-3,4]的連續(xù)最大和,然而,相對于子問題[-2, 1,-3,4]而言,[1,-3,4]是原來問題的子子問題,沒有必要再去求解,因?yàn)榍蠼庾訂栴}[-2, 1,-3,4]的最優(yōu)解時(shí),一定會(huì)考慮子子序列[1,-3,4],否則求解[-2, 1,-3,4]就是錯(cuò)誤的。


          綜上,使用暴力枚舉會(huì)對很多重復(fù)子問題計(jì)算,也就是說這個(gè)問題具備重復(fù)子問題特性!



          七 應(yīng)用動(dòng)態(tài)規(guī)劃求解


          滿足以上三個(gè)基本條件后,確定可以使用動(dòng)態(tài)規(guī)劃,而強(qiáng)大的動(dòng)態(tài)規(guī)劃,能將以上問題時(shí)間復(fù)雜度降到 O(n)。


          卡內(nèi)基梅大學(xué)一位教授首先提出此動(dòng)態(tài)規(guī)劃的解法,命名為 Kadane's algorithm,Kadane算法使用的決策策略,非常巧妙,非常簡潔:


          current_sum?= max(x, x + current_sum)


          其中 current_sum 初始值為:負(fù)無窮


          上面策略表達(dá)的含義:?


          如果 current_sum 小于 0,則更新current_sum 值為當(dāng)前迭代到的元素值 x;


          如果 current_sum 不小于 0,則 current_sum 值同時(shí)吸納 x 和上一時(shí)步的 current_sum,


          所以,無論 current_sum 大小,當(dāng)前迭代到?x 值總是會(huì)被吸納到 current_sum 中,這個(gè)策略保證了是連續(xù)的子數(shù)組,


          如果再發(fā)揮想象力,把 current_sum 定義為最大貢獻(xiàn)值,如果上一個(gè)迭代步的最大貢獻(xiàn)值大于0,就會(huì)把它吸納到當(dāng)前步的current_sum中,否則當(dāng)前步的current_sum值不會(huì)吸納之前迭代步的current_sum,只保留當(dāng)前元素 x 值。


          基于此更新策略,能夠求出任意一個(gè)迭代步的 current_sum,就題目中給定的數(shù)組:[-2,1,-3,4,-1,2,1,-5,4],


          初始狀態(tài),current_sum = float('-inf')?


          i = 0, x = -2, current_sum = -2?


          i = 1, x = 1,? current_sum = max(1, 1-2) = 1


          i = 2, x = -3, current_sum = max(-3, -3+1) = -2


          i = 3, x = 4, current_sum = max(4, 4-2) = 4


          i = 4, x = -1, current_sum = max(-1, -1+4) = 3


          i = 5, x = 2, current_sum = max(2, 2+3) = 5



          i = 6, x = 1, current_sum = max(1, 1+5) =?6



          i = 7, x = -5, current_sum = max(-5, -5+6) = 1



          i = 8, x = 4, current_sum = max(4, 4+1) = 5


          從中選擇最大的current_sum,便是原問題的最優(yōu)解,即為 6



          八 代碼


          弄懂以上分析后,最大子數(shù)組的動(dòng)態(tài)規(guī)劃,代碼非常簡潔:

          class?Solution:
          ????def?maxSubArray(self,?nums:?List[int])?->?int:
          ????????current_sum,?best_sum?=?float('-inf'),?float('-inf')

          ????????for?num?in?nums:
          ????????????current_sum?=?max(num,?num?+?current_sum)
          ????????????best_sum?=?max(current_sum,?best_sum)
          ????????
          ????????return?best_sum


          九 后續(xù)思考


          最大子數(shù)組和,上面給出了動(dòng)態(tài)規(guī)劃的解法,還可以使用遞歸的解法,時(shí)間復(fù)雜度也是O(n),但是空間復(fù)雜度卻為O(logn),所以最大子數(shù)組的最好解法還是動(dòng)態(tài)規(guī)劃。

          動(dòng)態(tài)規(guī)劃還常常使用表格,緩存之前各個(gè)狀態(tài)的解,通過空間換取時(shí)間,這個(gè)也是動(dòng)態(tài)規(guī)劃常用的技巧之一,但這卻不是動(dòng)態(tài)規(guī)劃最難構(gòu)思出來的地方,最難的還是設(shè)計(jì)每個(gè)狀態(tài)步的決策策略,這才是動(dòng)規(guī)的精髓。

          另外,不是所有的問題都有動(dòng)規(guī)的解法,比如目前全世界最難求解的旅行商問題,更復(fù)雜的多線路配送問題,都屬于NP問題,很難找到動(dòng)態(tài)規(guī)劃的解法,但是一旦找到動(dòng)規(guī)解法,它會(huì)將O(n!)問題降為O(n多項(xiàng)式)問題,收益也是巨大的!


          十 二叉樹的子樹最大和

          子數(shù)組的最大和問題是一維的,存在通過建立每個(gè)狀態(tài)步的最大收益,然后找出最大收益的動(dòng)規(guī)解法。那么,二叉樹的子樹最大和,就是二維的子數(shù)組最大和問題,同樣可以使用動(dòng)規(guī)解法,思路與本文一維子數(shù)組最大和極為相似,也是建立每個(gè)樹節(jié)點(diǎn)的最大收益,這道題在LeetCode上hard級(jí)別,大廠面試也會(huì)問道。

          輸入:[-10,9,20,null,null,15,7]

          ? -10
          ? ?/ \
          ? 9 ?20
          ? ? / ?\
          ? ?15 ? 7

          輸出:42

          基于本文的講解,再去看看這道題目,或許思路會(huì)豁然開朗。

          以上就是動(dòng)態(tài)規(guī)劃的入門解讀,我已經(jīng)將此文整理為PDF,需要PDF的微信我,備注:動(dòng)規(guī)



          不必打賞
          給我點(diǎn)個(gè)贊
          就心滿意足了


          算法刷題日記

          作者:zhenguo


          這是我的另外一個(gè)公眾號(hào):算法刷題日記,我正在努力打造它為精品公眾號(hào),只做算法刷題的推文推薦,目前已原創(chuàng) 60 多篇算法刷題的精品解讀。

          瀏覽 30
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  私人玩物爆乳 | 成人国产精品秘 久久久 | 日韩Aⅴ高清| 牛牛精品一区二区 | 亚洲国产精品欧美久久 |