最長公共子序列_筆記版+電子版
阿新 • • 發佈:2021-01-29
最長公共子序列
f [ i ] [ j ] f[i][j] f[i][j]——集合:所有在第一個序列的前 i i i個字母中出現,且在第二個序列的前 j j j個字母中出現的子序列 |
---|
屬性:最大值 |
遞迴版:
或許也不需要那麼費力想,先以遞迴的思想——列舉。
共有4
種情況:都不選,其中一個選(2
種),都選(
a
[
i
]
=
=
b
[
i
]
a[i] == b[i]
a[i]==b[i])。
-
a[i]
選,b[j]
不選:直接看dfs(i ,j + 1)
即可,若仔細想想dfs(i ,j + 1)
的情況其實有很多,並不是我們想的b[j]
一定不選而是繼續對
a
的後i+1
的個和b
的後j
個進行這4種情況的判斷。這4種情況
包含
了**a[i]
選,b[j]
不選,**這種情況,由於是取max,故並不影響。 -
a[i]
不選,b[j]
選:和1
一樣。 -
都不選其實是包含在
1
2
中的,比如:a[i]
選,b[j]
不選,然後繼續遞迴到
i
j+1
, 會繼續判斷上面說的幾種情況判斷,其中一種:
a[i]
不選,b[j+1]
選。那麼到這,a[i]
b[j]
都不選的情況是判斷了的。故不需要單獨判斷都不選
先食用遞迴版,然後用遞迴方程來理解與推出迴圈版
#include <iostream> #include <algorithm> using namespace std; const int n = 1010; char a[n], b[n]; int f[n][n]; int N, M; int dfs(int i, int j) { if (i == N + 1 || j == M + 1) return 0; if (f[i][j]) return f[i][j]; int res = 0; // 若相等 則一定都選 if (a[i] == b[j]) res = 1 + dfs(i + 1, j + 1); else // 不選a[i]選b[j] , 選a[i]不選b[j] res = max(dfs(i + 1, j), dfs(i, j + 1)); return f[i][j] = res; } int main() { cin >> N >> M; scanf("%s%s", a + 1, b + 1); cout << dfs(1, 1); cout << endl; // f矩陣 for (int i = 1; i <= N; i++) { for (int j = 1; j <= M; j++) cout << f[i][j] << ' '; cout << endl; } return 0; }
迴圈版:
理解了遞迴版,看一下DP方程,就很好理解啦~