Longest Common Subsequence. — Cracked Java
// Data Structures & Algorithms · Dynamic Programming
MidCodingAmazon

Longest Common Subsequence.

Problem. Given two strings, return the length of their longest common subsequence — characters appearing in both in the same relative order, not necessarily contiguous. "abcde" and "ace" → 3 ("ace").

The recurrence — the canonical 2D grid DP

State dp[i][j] = LCS length of the first i chars of a and first j chars of b. Compare the last characters:

if a[i-1] == b[j-1]:  dp[i][j] = dp[i-1][j-1] + 1          // match: extend
else:                 dp[i][j] = max(dp[i-1][j], dp[i][j-1]) // drop one char

Base cases: an empty prefix gives LCS 0, so row 0 and column 0 are zeros.

The brute force — enumerate all 2ᵐ subsequences of one string and test membership — is exponential. The DP is O(m·n).

O(m·n) tabulation

int longestCommonSubsequence(String a, String b) {
    int m = a.length(), n = b.length();
    int[][] dp = new int[m + 1][n + 1];     // row/col 0 are the empty-prefix base cases
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++)
            dp[i][j] = a.charAt(i - 1) == b.charAt(j - 1)
                ? dp[i - 1][j - 1] + 1
                : Math.max(dp[i - 1][j], dp[i][j - 1]);
    return dp[m][n];
}

O(m·n) time and space.

Space optimization — O(min(m, n))

Each row depends only on the current and previous row, so two 1D arrays (or one plus a saved diagonal) suffice:

int longestCommonSubsequence(String a, String b) {
    int m = a.length(), n = b.length();
    int[] prev = new int[n + 1], cur = new int[n + 1];
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++)
            cur[j] = a.charAt(i - 1) == b.charAt(j - 1)
                ? prev[j - 1] + 1
                : Math.max(prev[j], cur[j - 1]);
        int[] tmp = prev; prev = cur; cur = tmp;   // roll the rows
    }
    return prev[n];
}

Mark your status