🧮 2-D DP
二維狀態與網格上的動態規劃。
32 題
📖 分類導讀
二維動態規劃將狀態擴展到兩個維度,常見於字串比較、網格路徑、區間 DP 等問題。
Notes:
- 常見狀態定義:dp[i][j] 代表「前 i 個元素和前 j 個元素的最優解」
- 網格型 DP:狀態通常是座標 (i, j)
- 字串型 DP:狀態通常是兩個字串的索引 (i, j)
兩大家族
- 網格型:
dp[i][j]是「走到座標 (i, j)」的最優解,轉移多半來自上方與左方(dp[i-1][j]、dp[i][j-1])。最小路徑和、不同路徑數屬此類。 - 雙序列型:
dp[i][j]是「第一個字串前 i 個、第二個字串前 j 個」的最優解。最長公共子序列、編輯距離屬此類。
// 編輯距離:把 word1 變成 word2 的最少操作數
fun minDistance(word1: String, word2: String): Int {
val m = word1.length; val n = word2.length
val dp = Array(m + 1) { IntArray(n + 1) }
for (i in 0..m) dp[i][0] = i // 全刪
for (j in 0..n) dp[0][j] = j // 全插
for (i in 1..m) {
for (j in 1..n) {
dp[i][j] = if (word1[i - 1] == word2[j - 1]) {
dp[i - 1][j - 1] // 字元相同,不花操作
} else {
1 + minOf(
dp[i - 1][j], // 刪
dp[i][j - 1], // 插
dp[i - 1][j - 1] // 改
)
}
}
}
return dp[m][n]
}
NOTE
換個視角,編輯距離其實是網格圖上的最短路徑:把 (i, j) 當節點,「刪/插/改」是權重 1 的邊、「字元相同」是權重 0 的邊,求左上到右下的最短路。許多 2D DP 都能這樣翻譯成圖問題——這也是 DP 與最短路演算法的共通血緣。
空間優化
網格與雙序列型若 dp[i][*] 只依賴 dp[i-1][*],可把二維壓成一維滾動陣列,空間從 O(mn) 降到 O(n)。
跨倉庫導讀
- 對應理論章節:動態規劃