intermediate8 min read·Updated October 5, 2026
Longest Common Subsequence Explained: Tracing 'abcde' and 'ace'
Master the longest common subsequence algorithm through a visual grid walkthrough of 'abcde' and 'ace'. Build a mental model for dynamic programming.
By Learnisim AI·Published October 5, 2026
LEARNING ARCSetup → Model in the example → Full trace → Twist → Edge cases → Apply
PREREQUISITES
- short strings
- basic 2D arrays
Why
Why simple string matching breaks for non-contiguous overlap
Phase 1: The gap problem in string comparison
Imagine you are comparing two DNA strands, two text revisions, or two user search queries to find what they share. Given
text1 = "abcde" and text2 = "ace", your first instinct might be to look for a continuous block of matching characters. But a standard substring search fails: "abcde" contains "a", "b", "c", "d", and "e", and "ace" contains "a", "c", and "e". While they share "a", "c", and "e", those letters appear in that exact relative order without needing to be right next to each other.If you checked for a contiguous substring, you would find at best a length of 1 (like
"a" or "c") because the letter "b" breaks the contiguous block between "a" and "c" in the first string. Yet intuitively, "ace" feels like a much stronger match that preserves the sequence order. Without a method to skip over insertions and deletions while preserving left-to-right order, algorithms miss these scattered structural similarities.Now consider a second contrast: comparing
text1 = "abc" and text2 = "def". Here, no characters match in order at all, yielding an expected result of 0. How do we systematically distinguish between a partial interleaved overlap like "ace" and total disjointness like "def" without checking every single exponential combination of skipped letters?Model
The Subsequence Grid: Visualizing Choices Across Two Strings
Phase 2: The 2D Grid Model
To understand how to track overlapping characters without requiring them to sit side-by-side, we must picture a two-dimensional grid. Imagine placing text1 = "abcde" along the columns and text2 = "ace" along the rows of a matrix. Each cell in this grid represents a decision point: when we compare a character from "abcde" against a character from "ace", what is the length of the longest common subsequence up to that exact pair of indices?
If the character from text1 matches the character from text2, we take the diagonal history from the top-left cell and add 1. If they do not match, we take the maximum value from either the cell directly above us or the cell directly to our left. This grid formulation transforms a messy search problem into a structured path-finding exercise across a matrix of size .
For our locked example, the top row and left column start entirely at zero, acting as the boundary condition when one of the strings is empty.
Try this: Given text1 = "abcde" and text2 = "ace", sketch the dimensions of the comparison grid and explain what cell (0,0) represents.
Worked example
Tracing the LCS Grid for text1 = "abcde" and text2 = "ace"
Phase 3: Building the DP Table
Now we take the 2D grid model from the previous phase and execute it step by step on our first running example:
text1 = "abcde" and text2 = "ace". We will build a matrix dp of size to track the length of the longest common subsequence at every prefix combination.Given
-text1 = "abcde" (length , rows to 5)-
text2 = "ace" (length , columns to 3)- Base case:
dp[i][0] = 0 and dp[0][j] = 0 for all .Steps
1. Initialize the Grid: Create a table initialized with zeros to account for empty prefix comparisons.
2. Row 1 (
- Compare with
- Compare with
text1[0] = 'a'):- Compare with
text2[0] = 'a': Match! dp[1][1] = dp[0][0] + 1 = 1.- Compare with
text2[1] = 'c' and text2[2] = 'e': No match, carry forward max left or up dp[1][2] = 1, dp[1][3] = 1.3. Row 2 (
- Compare with
text1[1] = 'b'):- Compare with
'a', 'c', 'e': No matches in this row. Values copy down from above row 2 remains [0, 1, 1, 1].4. Row 3 (
- Compare with
- Compare with
- Compare with
text1[2] = 'c'):- Compare with
text2[0] = 'a': No match dp[3][1] = 1.- Compare with
text2[1] = 'c': Match! dp[3][2] = dp[2][1] + 1 = 2.- Compare with
text2[2] = 'e': No match dp[3][3] = max(dp[3][2], dp[2][3]) = 2.5. Row 4 (
- No matches with
text1[3] = 'd'):- No matches with
'a', 'c', or 'e'. Row 4 copies row 3 [0, 1, 2, 2].6. Row 5 (
- Compare with
- Compare with
text1[4] = 'e'):- Compare with
text2[0] = 'a' and text2[1] = 'c': No new matches dp[5][1] = 1, dp[5][2] = 2.- Compare with
text2[2] = 'e': Match! dp[5][3] = dp[4][2] + 1 = 2 + 1 = 3.Result
The bottom-right celldp[5][3] contains 3, which is the length of the longest common subsequence ("ace").Try this: Using the same dynamic programming recurrence, trace the resulting bottom-right value for text1 = "abc" and text2 = "def". What is the final value of dp[3][3]?
Practice
Practice: Predicting DP State Changes for Alternative Inputs
Phase 4: Practice
Now that you have traced the overlapping case for
text1 = "abcde" and text2 = "ace", let us test your understanding on a completely disjoint pair where no characters match: text1 = "abc" and text2 = "def".Recall the core transition rule from the previous phase:
Mentally construct or sketch the dynamic programming table (including the initial zero-row and zero-column) for
text1 = "abc" and text2 = "def".The Question:
What will be the final value stored in the bottom-right cell
What will be the final value stored in the bottom-right cell
dp[3][3] of the matrix, and why does this value reflect the longest common subsequence for text1 = "abc" and text2 = "def"?Apply
Applying LCS Patterns to Real-World Text Diffing
Phase 5: Applying the Pattern Beyond Toy Strings
Now that you have traced the 2D dynamic programming grid for text1 = "abcde" and text2 = "ace" and verified the zero-match behavior for text1 = "abc" and text2 = "def", let us see where this abstract structure appears in the wild. The exact same DP matrix that pairs characters without requiring contiguous blocks is the engine behind modern file comparison tools like
git diff and biological sequence alignment in bioinformatics. Instead of comparing single characters like 'a', 'c', and 'e', line-based diff utilities treat entire text lines as atomic elements in our sequences.Imagine you are building a simplified version of
git diff to compare two configuration files. File A has three lines: a database URL, a port number, and a timeout limit. File B reorders them and updates the port number. By mapping each line to an element in our 1D or 2D array, the longest common subsequence reveals which lines remained untouched across edits, while the omitted indices highlight deletions and insertions. You are no longer just counting lengths; you are reconstructing the history of edits by walking backward from the bottom-right cell of your grid.When adapting this algorithm to new domains, the primary task is defining your equivalence relation. In our toy example, equality meant strict character identity (). In real-world applications, equality might mean matching normalized strings, case-insensitive tokens, or genomic base pairs with allowed mutation thresholds. The recurrence relation remains identical, but your base comparison function changes to suit the domain data.
FAQ
What is the LCS of 'abcde' and 'ace'?
The longest common subsequence is 'ace', giving a length of 3. Characters do not need to be contiguous, but they must appear in the same relative order.
What happens if two strings have no characters in common, like 'abc' and 'def'?
The longest common subsequence length is 0, since no characters overlap between the two strings.
What is the time and space complexity of the standard LCS dynamic programming solution?
The time complexity is O(m × n) and space complexity is O(m × n) for two strings of lengths m and n, though space can be optimized to O(min(m, n)).
How is a subsequence different from a substring?
A substring requires contiguous characters from the original string, whereas a subsequence allows characters to be skipped as long as their relative order is preserved.