Longest Common Subsequence

Medium Dynamic Programming Strings Original on LeetCode

Longest Common Subsequence is a medium dynamic programming problem solved with the strings pattern. The best approach, optimal (two rows), runs in O(m · n) time and O(n) space. Below are 3 approaches in Java, from recursion up.

Problem

Return the length of the longest common subsequence of two strings: the longest sequence of characters that appears in both, in order, but not necessarily contiguously.

Examples

Example 1

Input
text1 = "abcde", text2 = "ace"
Output
3

Example 2

Input
text1 = "abc", text2 = "def"
Output
0

Constraints

  • 1 <= length <= 1000; lowercase letters.
  • A subsequence keeps order but may skip characters.

Animated walkthrough

A narrated, step-by-step animation that builds the solution from the idea up. Press play, or step through it at your own pace.

Concepts first, then the problem and every approach, step by step.

Space to play or pause · ← → to jump a step · click or drag the bar to seek

Solutions

Try it yourself first. Then compare: each approach lists its idea, the steps, its time and space, and the Java code.

ApproachTimeSpace
RecursionO(2^(m + n))O(m + n)
Tabulation (2D)O(m · n)O(m · n)
Optimal (two rows)O(m · n)O(n)

1Recursion

TimeO(2^(m + n))
SpaceO(m + n)

Compare the last characters; match → take both; otherwise try dropping either one.

  1. f(0, ) = f(, 0) = 0.
Java
class Solution {
    public int longestCommonSubsequence(String a, String b) {
        return f(a, b, a.length(), b.length());
    }

    private int f(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 + f(a, b, i - 1, j - 1);
        return Math.max(f(a, b, i - 1, j), f(a, b, i, j - 1));
    }
}

2Tabulation (2D)

TimeO(m · n)
SpaceO(m · n)

dp[i][j] = LCS of the first i characters of a and the first j of b.

  1. Match: dp[i - 1][j - 1] + 1. Else max(dp[i - 1][j], dp[i][j - 1]).
Java
class Solution {
    public int longestCommonSubsequence(String a, String b) {
        int m = a.length(), n = b.length();
        int[][] dp = new int[m + 1][n + 1];
        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];
    }
}

3Optimal (two rows)

TimeO(m · n)
SpaceO(n)

Keep only the previous and current rows.

  1. Swap rows after each i.
Java
class Solution {
    public 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[] t = prev; prev = cur; cur = t;
        }
        return prev[n];
    }
}

Edge cases to test

  • No common letters
  • One string inside the other

Hints

Hint 1

If the last characters match, they are both in the LCS: 1 + dp[i - 1][j - 1]. Otherwise drop one of them: max(dp[i - 1][j], dp[i][j - 1]).

FAQ

What is the best time complexity for Longest Common Subsequence?

Optimal (two rows) runs in O(m · n) time and O(n) extra space.

Which pattern does Longest Common Subsequence use?

It is a dynamic programming problem that uses the strings pattern. Other problems with the same pattern: Edit Distance, Longest Palindromic Subsequence, Minimum Insertion Steps to Make a String Palindrome.

Is there a brute force solution for Longest Common Subsequence?

Yes. Recursion takes O(2^(m + n)) time and O(m + n) space. Compare the last characters; match → take both; otherwise try dropping either one.

Which edge cases should I test for Longest Common Subsequence?

No common letters; One string inside the other.