DP的模板题

将s1作为短的字符串,s2作为长的字符串。

考虑空间复杂度n*m的做法,定义dp[n][m],dp[i][j]表示考虑s2的前 i 位和s1的前 j 位的最长公共子序列的结果

状态转移:

if (s2[i] == s1[j]) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] + 1);

else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

考虑到在转移方程中,只存在两行数组之间的转换,既只有dp[i][*]和dp[i - 1][*]的转换。可以使用一个两行的数组来代替整个数组。既可以做到时间复杂度min(n, m);

#include <bits/stdc++.h>
using namespace std;

int main() {

    int n, m;
    cin >> n >> m;
    string s1, s2;
    cin >> s1 >> s2;
  
    if(n > m) {
        int t = n;
        n = m;
        m = t;
        string x = s1;
        s1 = s2;
        s2 = x;
    }
    vector<vector<int>> dp(2, vector<int>(n + 1, 0));
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (s2[i] == s1[j]) {
                dp[1][j + 1] = max(dp[0][j + 1], dp[0][j] + 1);
            } else {
                dp[1][j + 1] = max(dp[0][j + 1], dp[1][j]);
            }
        }
        for (int j = 0; j <= n; j++) {
            dp[0][j] = dp[1][j];
        }
    }
    cout << dp[0][n] << '\n';
}