lCS(最長公共子串)

_Yxc發表於2024-04-15

之前一直寫的最長公共子序列,從來沒寫過最長公共子串這個演算法,也因為這個,在今年的藍橋杯省賽中有個題目用的暴力字串匹配,導致了丟分(也可能拿不到省一了,哎)

其實就是一個二維的dp,dp[i][j]表示第一個以i結尾,第二個以j結尾的最長長度。

1 初始化,第一個串的下標按行儲存,第二個串的下標按列儲存。第一列按行遍歷,表示當前在第一個串s的第i個字元時,t串的第1個字元時,是否相等。
按列遍歷,表示s串第一個字元和t串的第j個字元是否相等。

2 狀態轉移 如果s[i] == t[j] , dp[i][j] = dp[i - 1][j - 1] + 1,否則 = 0;

3 輸出結果 在遍歷的過程中保留結果即可。

4 擴充 如何輸出這個串?在遍歷的過程中如果ans被更新,則記錄某個串的結尾下標,然後直接按記錄的下標-ans輸出即可。

void solve(){
string s, t;
cin >> s >> t;

int n = s.size();
int m = t.size();

vector<vector<int>> dp(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; ++i){
    if (s[i - 1] == t[0]){
        dp[i][1] = 1;
    }
}
for (int i = 1; i <= m; ++i){
    if (t[i - 1] == s[0]){
        dp[1][i] = 1;
    }
}

int ans = 0;
int index = 0;
for (int i = 1; i <= n; ++i){
    for (int j = 1; j <= m; ++j){
        if (s[i - 1] == t[j - 1]){
            dp[i][j] = dp[i - 1][j - 1] + 1;
        }
        else{
            dp[i][j] = 0;
        }
        if (changeMax(ans, dp[i][j])){
            index = i - ans;
        }
    }
}

cout << ans << '\n';
cout << s.substr(index, ans) << '\n';

}

相關文章