Longest Common Subsequence

MediumString DP · Two-Sequence Table🧩 String DPLeetCode #1143 ↗Updated

Problem

Given two strings text1 and text2, return the length of the longest string that is a subsequence of both (characters kept in their original order, but not necessarily adjacent). Return 0 if they share no character.
Input"abcde", "ace"Output3 ("ace")
Input"abc", "abc"Output3
Input"abc", "def"Output0

1 ≤ text1.length, text2.length ≤ 1000  ·  lowercase English letters only

Try it yourself

Java
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Compare the last characters of two prefixes: if they match, they can both end the LCS (1 + lcs(i-1, j-1)); if not, one of them is useless, so take max(lcs(i-1, j), lcs(i, j-1)). Only (m+1)(n+1) distinct prefix pairs exist.
PatternString DP

Instinct Two strings compared char by char (match, edit, interleave) means dp[i][j] over prefixes; one string's palindromes or splits means dp[l][r] or dp[i].

Memory hack Match? Go diagonal. Mismatch? Ask the neighbours. Up drops a char from s, left drops one from t, diagonal uses both.

Open the String DP guide →

Approaches

Brute ForcePlain Recursion on Prefixes

Time O(2m+n)Space O(m + n)

lcs(i, j) = LCS of the first i and j characters. On a mismatch it branches twice, and each branch shrinks i + j by only one, so the call tree can have ~2m+n nodes — the same (i, j) pairs are solved over and over.

Java
public int longestCommonSubsequence(String text1, String text2) {
    return lcs(text1, text2, text1.length(), text2.length());
}
private int lcs(String a, String b, int i, int j) {
    if (i == 0 || j == 0) return 0;
    if (a.charAt(i - 1) == b.charAt(j - 1)) return 1 + lcs(a, b, i - 1, j - 1);
    return Math.max(lcs(a, b, i - 1, j), lcs(a, b, i, j - 1));
}

Captures the recurrence perfectly, but exponential; hopeless beyond ~20 chars.

At a glance

LevelApproachTimeSpace
Brute ForcePlain Recursion on PrefixesO(2m+n)O(m + n)
Better2-D Tabulation (Bottom-Up)O(m·n)O(m·n)
Optimal1-D Rolling RowO(m·n)O(min(m, n))
Common pitfalls
  • Confusing subsequence with substring — mismatches must not reset to 0.
  • Off-by-one: dp[i][j] uses charAt(i-1), charAt(j-1).
  • Rolling array without saving diag — top-left gets overwritten.
Interview tips
  • Write the recurrence first, then point out the overlapping (i, j) states.
  • Show the progression recursion → memo/table → one row.
  • LCS is the template for Edit Distance and Delete Operations for Two Strings.
Pattern
Two-sequence DP (prefix × prefix) → align/compare two strings or arrays element by element.
My notes saved in this browser