三道簡單的動態規劃題
有 m x n 個格仔,機械人在最左上角的格仔,星星在最右下角的格仔。機械人只能向左和向下走。
問:機械人拿到星星,總共有多少種拿法?
如下圖:
思路:問題其實就是從左上角走到右下角,有多少種走法。
如果倒過來看,站在右下角的角度,走到右下角,只有2種可能:
一是從右下角格仔的左邊走來;二是從右下角格仔的上方走來。
所以,假設走到右下角格仔的左邊的格仔有 x 種走法,走到右下角格仔的上面的格仔有 y 種走法,
那麼,走到星星的位置總共就是有 x + y 種走法。
想到這裡,自然會去想,走到左邊格仔和走到上面格仔分別有多少種走法呢,即 x 和 y 應怎麼計算呢?
當然仍然是由目標格仔的左邊和上面的格仔的數字加起來。
於是,這道題很自然的就變成了一道填表題:
假設目標格仔的下邊是 u 和 v,那麼公式為:
array[u][v] = array[u-1][v] + array[u][v-1]
現在來考慮邊界條件:
u-1 和 v-1 都必須大於等於0,即,u和v都大於1;
那麼,當 u 或 v 為 0 的時候,array[u][v]是多少呢?
閱讀題目,自然而然地知道,當u為0或v為0,即第1排和第1列中的所有格仔都應該填1,即到達這樣的格仔只有一種走法。
於是,公式更新為:
當 u == 0 或 v == 0,
array[u][v] = 1
當其他時候,
array[u][v] = array[u-1][v] + array[u][v-1]
第一排和第一列先都填上1,然後其他格仔就順著填就填出來了。右下角的格仔自然最後也就填出來了。
程式如下:
class
solution
for(
int i=
0; i
)for
(int i=
0; i
)for
(int i=
1; i
int result = array[m-1]
[n-1];
for(
int i=
0; i
)delete
array;
return result;}}
;
第2題和第1題很像。仍然是 m x n 個格仔,機械人從左上角到右下角拿星星。
不同之處是, m x n 個格仔中會放置若干個障礙物,遇到障礙物自然被阻擋不能前進。
問:機械人拿到星星有多少種方法?
如下圖:
思路:首先,要想一下,障礙物如何表示。這很簡單,令有障礙物的格仔的數字為 -1 即可。
然後,我們要想一下 array[u][v] 的公式該怎麼改寫了。
假設目標格仔的上面是障礙物,那麼 array[u][v] = array[u-1][v] + 0;
假設目標格仔的左邊是障礙物,那麼 array[u][v] = array[u][v-1] + 0;
假設上面和左邊都是障礙物,那麼自然 array[u][v] = 0
現在,要開始考慮令 u-1 < 0 和 v-1 < 0 的情況,即第一排和第一列,該如何初始化?
上一題中,第一排和第一列都是初始化為 1 的;但是現在有障礙物之後,就不能都初始化為 1 了。
初始化完第一排和第一列之後,剩下的所有格仔就依然用填表法即可解決。**如下:
class
solution}}
for(
int j=
1; j
)break;}
else
}for
(int i=
1; i
)break;}
else
}for
(int i=
1; i
return obstaclegrid[m-1]
[n-1];}};
有乙個 m x n 的格仔矩陣。裡面填滿了非負整數。要求:從左上角到右下角找一條路徑,使得這條路徑上所有的數字相加之和最小。
如下圖:
思考:這道題最直觀的思考,很可能是這樣的:
左上角的格仔就像是一棵二叉樹的root,它的左兒子是下面的格仔,右兒子是右邊的格仔。
然後左兒子和右兒子又分別有自己的左右子樹。這就構成了一棵龐大的二叉樹。
再然後就是遍歷這棵二叉樹中能到達右下角葉子節點的所有路徑,找出其中的最小值。
讀者可以畫一畫,這棵二叉樹中有太多冗餘的部分。所以生成這顆二叉樹再計算肯定不是正解。
為了避免生成冗餘的部分,就要生成一種有向無環圖。當這個有向無環圖生成完畢之後,還要遍歷以找到最小值。這2個過程都是比較複雜的,而且也比較耗時。
有了之前的2題做啟發,這道題也倒過來想呢?
好了,想到這裡,我們忽然發現,這道題也是可以用填表法來填的啊!只不過要倒著推。
**如下:
class
solution
result.
push_back
(vecrow);}
result[m-1]
[n-1
]= grid[m-1]
[n-1];
for(
int col=n-
2; col>=
0; col--
)for
(int row=m-
2; row>=
0; row--
)for
(int i = m-
2; i >=
0; i--)}
return result[0]
[0];}};
(完) 三道題理解動態規劃
動態規劃是演算法導論中介紹的最重要的幾種基本演算法之一,因為好長時間沒有看書,再加上原來就理解的不深入,所以早就忘的差不多了,這兩天正好因為一道面試題複習一下。用幾句話描述動態規劃問題如下 乙個問題可以分解若干子問題,每乙個子問題為一種狀態,求出每乙個狀態的最優解,進而在它的幫助下求出下乙個狀態的最...
刷題86 動態規劃(三)
題目鏈結題目描述 給定乙個非負整數 num。對於 0 i num 範圍中的每個數字 i 計算其二進位制數中的 1 的數目並將它們作為陣列返回。示例 1 輸入 2 輸出 0,1,1 示例 2 輸入 5 輸出 0,1,1,2,1,2 高階 題目分析 法一 動態規劃 找規律 奇數二進位制中1的個數比前乙個...
LeetCode刷題 動態規劃(三)
最長公共子串行問題,最基本的問題是在兩個字串中找出最長公共字串。方法是使用雙指標 i,j遍歷兩個字串,建立二維 dp 陣列,通過填表獲得結果。1143,最長公共子串行,medium 583,兩個字串的刪除操作,medium 712,兩個字串的最小ascii刪除和,medium 1143,最長公共子串...