關於dfs和dp的思考
阿新 • • 發佈:2018-12-30
一、問題
問題1:給幾個數字,輸出排列的種樹;或者是八皇后問題
問題2:給定一字串,字串裡有*,*可以換成0或者1,輸出各種可能情況。(比如說,字串是01*78aljdou*a,可以變成01178aljdou1a、01078aljdou1a、01078aljdou0a、01078aljdou0a四種情況。
問題3:輸入為字串,是一串數字,輸出各種可能的ip地址(leetcode上Restore IP Addresses)
問題4:在leetcode上一道題,decode ways。 'A' -> 1 'B' -> 2 ... 'Z' -> 26
問題5:給一個數字,如果是奇數,可以加一和減一操作;如果是偶數,可以除以2。我們最終要讓這個數變為一,最少的步數是多少?
問題6:給定一串字串,再給一個字典,將字串分解為字典中存在的單詞,並將各種情況打印出來。
二、dfs
面對上面這些題時,你仔細比較一下,都是輸出各種可能情況,可以看做一種排列問題。怎麼用dfs解決這種問題呢? 首先就用問題2舉個例子,當訪問到*的時候,我需要解決當前問題,可以把*換成0和1兩種情況,剩下的問題又成了獨立的問題,再遞迴呼叫處理剩下的問題。稍微用樸素的語言歸納一下,可以先列舉當前情況,再遞迴解決後面各種出現的情況.最後寫一個虛擬碼吧,來說明這種思路。
dfs(整個問題){
取當前一部分,列舉當前情況,並解決
dfs(剩下的問題)
}
三、dp
在解決上面的第3、4個問題時,你會發現,有很多重複計算,所以說要保留重複計算的部分,我可以把它分解為一個個子問題,怎麼把一個子問題程式設計再大一點的問題呢?這就要尋找一種大問題與小問題之間的遞推關係。下面就用第四個問題來舉例,分析一下怎麼得到這個遞迴關係。以問題3為例,首先,從頭到尾掃這個String,從第一位到dp[i]這一位組成的String,有多少種解碼組合。(儲存重複運運算元問題)
可以有兩種情況:(分解子問題)1)只解析當前字元,有dp[i-1]種;2)解析i-1和i時,那麼dp[i-2]種
那麼遞迴關係得到dp[i]=dp[i-1]+dp[i-2];(求解最優子結構
3.1 dp總結
我覺得可以寫成虛擬碼,如下分解子問題,子問題求解,並且儲存子問題的解,防止重複運算
從眾多子問題中,並選取最優的子問題解,得到大問題與子問題的遞推關係
從虛擬碼和上面分析問題的方法中,我們也可以有比較重要的三點:
1)分解子問題,怎麼劃分子問題?其實是一個分治的思想
2)儲存子問題的解,其實就是以空間換時間,防止重複求解
3)最優子結構,比較所有種可能性,得到全域性最優