The longest sequence appearing (not necessarily contiguously) in both strings.

The recurrence

int lcs(const string& a, const string& b) {
    int n = a.size(), m = b.size();
    vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            dp[i][j] = (a[i-1] == b[j-1]) ? dp[i-1][j-1] + 1
                                          : max(dp[i-1][j], dp[i][j-1]);
    return dp[n][m];
}

time and space; space with a rolling array.

Reconstructing the subsequence

string reconstruct(const string& a, const string& b, vector<vector<int>>& dp) {
    string res;
    int i = a.size(), j = b.size();
    while (i > 0 && j > 0) {
        if (a[i-1] == b[j-1]) { res += a[i-1]; i--; j--; }
        else if (dp[i-1][j] >= dp[i][j-1]) i--;
        else j--;
    }
    reverse(res.begin(), res.end());
    return res;
}

Needs the full table. With only two rows, use Hirschberg’s algorithm time, space, and it still produces the actual subsequence.

Beating

SituationMethodTime
Both strings are permutationsmap to indices, run LIS
One string has few distinct charactersHunt-Szymanski, = matching pairs
Small alphabet, need raw speedbit-parallel (Crochemore-Iliopoulos-Pinzon)
The answer is known to be short/longbanded DP around the diagonal

The permutation trick

If and are permutations of the same multiset with distinct elements, replace each element of by its position in . A common subsequence of the two is exactly an increasing subsequence of that new array. instead of .

Lower bound: no algorithm exists for general LCS unless the Strong Exponential Time Hypothesis fails. The quadratic barrier is real.

ProblemDifference
Longest common substring (contiguous)dp[i][j] = dp[i-1][j-1]+1 on match, 0 otherwise; or use a suffix automaton for
Edit distanceminimisation with insert/delete/replace
Shortest common supersequence
Longest palindromic subsequenceLCS of and
Minimum insertions to make a palindrome
LCS of strings — NP-hard in
Longest common increasing subsequence with a running maximum
Diff (Myers’ algorithm)LCS with an algorithm where is the edit distance — what git diff uses

The palindromic subsequence reduction is the most reused: LPS = LCS, so any LCS code solves palindrome problems for free.

Counting distinct LCS

Add a count array alongside the length array, being careful not to double-count when both dp[i-1][j] and dp[i][j-1] achieve the maximum — subtract dp[i-1][j-1]’s count by inclusion-exclusion when the characters differ and both branches tie.

See also: Edit Distance · LIS · Hirschberg