1. 程式人生 > 其它 >最長公共子序列_筆記版+電子版

最長公共子序列_筆記版+電子版

技術標籤:演算法學習筆記

最長公共子序列

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-S1o8lA1O-1611829404081)(https://s3.ax1x.com/2021/01/28/y9BOc6.jpg)]

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])。

  1. 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,故並不影響。

  2. a[i]不選,b[j]選:和1一樣。

  3. 都不選其實是包含在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方程,就很好理解啦~