首先聲明一下,我沒有賣焦慮,是我本身焦慮了。其次,要感謝個人師傅,西湖區最帥.....前端
好了,言歸正傳,在leetCode評論區你均可以看到 lucifer,簡稱路西法大佬;他的題解纔是符合人類思惟的思考方式,思考的點都是很深刻淺出的。git
爲何要刷算法呢?由於如今大前端時代,而前端開發確實是比其它領域要稍微簡單一點的,注意,我並無說前端領域簡單,是入門相對簡單。入門簡單,就意味着入門的人會很是的多,那怎麼在衆多的初級前端中脫穎而出呢?我選擇了刷算法,刷算法有如下幾點好處。算法
你說的我都會,我也能看得懂,爲何一說/看就會,一寫就費呢?數組
由於大多數題解,甚至是leetcode評論區的題解,只會告訴答案,不會告訴你思考答案的方式。或者有些會告訴你怎麼思考,可是他們都是經驗豐富的dp選手,思考方式徹底不適合新手,一個動態轉移方程莫名其妙的就出來了???滿臉的黑人問號,我曾經也是這樣走過來的,再次感謝路西法大佬的指點。markdown
到底咱們要以什麼方式來學習動態規劃呢?個人建議是硬着頭皮先刷點簡單的,層層遞進,再刷點困難的;刷題的過程當中千萬不能浮躁,不要爲了AC而AC,而是要經過本身耐心的觀察,抽象,練習,概括總結;遞歸直至理解dp,熟悉dp。真的沒有什麼快捷的方式,若是有,都是騙人的。這裏,結合實戰來帶你們過一遍,用符合人類的思考方式徹底扒開動態規劃的褲子,學習(gandiao)動態規劃。ide
若是你不熟悉動態規劃,或者徹底不瞭解,我建議你先看看我上一篇 動態規劃 的文章。oop
好了,咱們直接上菜,先來看看 題目 ;post
不要多想,咱們先以符合人類最簡單的思惟方式暴力求解,再根據狀態樹考慮如下兩點。學習
那這題怎麼暴力呢?直接枚舉nums,以nums[i]爲起點,不斷的加到最後一位,加的過程當中維護一個最大值便可,我寫下代碼。千萬不要看不起暴力求解,是dp的突破口!ui
咱們來看下這個暴力的狀態樹,我只畫出前面最長的兩個分支,其它自行腦補。
分析一下這個暴力狀態樹兩個分支,很明顯答案都是是 [4,-1,2,1] ,後一個分支比前一個分支少一個-2,也就是問題的規模變小了,答案依然是最優的,這就存在最優子結構。
咱們在算第二個分支的時候,其實前面第一個分支已經算過了,這就是重複子問題。
通常這種最值型,都比較適合dp來求解;如何能快速的用dp求解,就靠你本身去攢經驗了。
狀態定義的對不對,直接是決定了你的dp方程式對不對,從而決定了你dp的方式對不對;
在【定義狀態】以前,咱們先要搞清楚兩個東西,一個是【狀態】,一個是【選擇】;
注意:這裏的【狀態】和【定義狀態】是兩個東西,【狀態】是題目給出的條件,會影響結果的條件,而定義【定義狀態】是爲了明確dp方程式的含義,以便後面根據狀態的變化,利用數學概括法得出狀態轉移方程,說白了就是找規律。
舉個例子,x + y = z,你必需要明確你的x,y,z是啥,你才能寫出這樣的狀態轉移方程;
到這裏,咱們明確了【狀態】和【選擇】,而定義好轉移方程的狀態;咱們必需要有如下兩個意識。
以題目爲例,nums = [-2,1,-3,4,-1,2,1,-5,4],最後一步是什麼?最優策略中使用的最後一個選擇是什麼?很明顯這道題的最後一個選擇是nums[6] = 1,若是【不選擇】1,上面咱們說過了,就是另起爐竈;若是選擇1,答案就是最終的 [4,-1,2,1];
根據以上的兩點,結合明確的兩個東西,一個是【狀態】,另外一個【選擇】
到這裏,狀態的定義咱們就能夠很明確的得出來了。
dp[i] = x,表示以 nums[i] 結尾的最大子序和爲x; i < nums.length
必定要想清楚狀態的定義,狀態的定義直接是決定了你的轉移方程對不對,dp的姿式對不對;
根據上面狀態的定義分析,咱們來找下規律(數學概括法);nums[i] 是一個個的狀態;對於每一個狀態,咱們能夠選擇,或者不選擇,若是選擇以nums[i]爲結果,那答案就是 nums[i] + dp[i-1],由於要連續,全部得加上前面的;若是不選擇,就是另起爐竈,以nums[i]開頭;枚舉全部的狀態,取兩種選擇的最大值,不就是答案了嗎?這就是狀態轉移方程了;
dp[i] = max(nums[i],dp[i - 1] + nums[i]),i > 1
由於咱們枚舉全部的狀態,取兩種選擇的最大值就是答案,因此邊界就是數組長度;初始值是什麼呢?很明顯就是數組自己,即dp[i] = nums[i];
必定要明確上面的狀態定義,轉移方程,邊界和初始值纔開始寫代碼,有一點不明白都不能寫代碼,否則基本一寫就費。想清楚了寫代碼也要很是細心。
咱們用一樣的套路解決乘積最大子數組
暴力求解就不解釋了,同上;
先來明確 【狀態】 和 【選擇】,這題一樣的,狀態就是一個個 nums[i],而對於每一個 nums[i] 狀態,一樣用是選或不選兩個選擇;可是這題有一個比較隱晦的條件,須要考慮進去,就是兩個數相乘:
那咱們在枚舉全部的狀態時候,根據這兩個條件,不斷的維護最大最小值,遇到負數就乘以最小值,遇到正數就是乘以最大值便可。結果只和最大最小值有關係,那咱們枚舉狀態不斷更新這兩個值就能夠求出答案了,其實若是是遇到0,狀況也是同樣的;
狀態的定義:
初始條件就是第一個數nums[i]
這裏直接給出代碼了。QAQ
我覺的dp是最能體現代碼功底的,爲何呢?由於它難。
必定要多練習,看懂了只是我懂了,你要真懂必須多練;
另外推薦幾個我以爲寫得還不錯的文章和視頻,沒有打廣告QAQ