LESSON 59 · ADVANCED4 min read

Two-Dimensional Dynamic Programming: Longest Common Subsequence and Edit Distance

Formulate 2D dynamic programming recurrence relations, table state transitions, and space-optimization techniques for Longest Common Subsequence (LCS) and Levenshtein Edit Distance.

OpenJDK 21+ (LTS)Free to readModule 15 of 15
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Construct 2D DP state tables for Longest Common Subsequence and Levenshtein Edit Distance
  • Trace optimal alignment paths backward through the DP table to reconstruct diff operations
  • Optimize space complexity from O(m * n) to O(min(m, n)) using rolling two-row buffers

01The Invariant of Longest Common Subsequence (LCS)

The Longest Common Subsequence (LCS) problem finds the length of the longest subsequence present in both strings text1 and text2 in the same relative order (not necessarily contiguous). LCS is the mathematical foundation of git diff, biological DNA alignment (BLAST), and plagiarism detection systems.

Let dp[i][j] represent the length of the LCS of text1[0..i-1] and text2[0..j-1]. We establish the fundamental recurrence relation:

1. If text1[i-1] == text2[j-1]: The characters match! They extend the LCS of the prefixes: dp[i][j] = 1 + dp[i-1][j-1].

2. If text1[i-1] != text2[j-1]: The characters do not match. The best subsequence comes from either skipping text1's character or text2's character: dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]).

example.js☕Java
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

02LCS 2D Table Trace

Tracing text1 = 'ABCDE' and text2 = 'ACE' across the 2D DP matrix illustrates how matches propagate diagonally while mismatches inherit from top and left neighbors:

notes.txtPlain text
+---+---+---+---+---+|   | ø | A | C | E |+---+---+---+---+---+| ø | 0 | 0 | 0 | 0 || A | 0 | 1 | 1 | 1 | (Match 'A': 1 + dp[0][0])| B | 0 | 1 | 1 | 1 | (Mismatch: max(dp[1][j], dp[2][j-1]))| C | 0 | 1 | 2 | 2 | (Match 'C': 1 + dp[2][1])| D | 0 | 1 | 2 | 2 | (Mismatch: max(dp[3][j], dp[4][j-1]))| E | 0 | 1 | 2 | 3 | (Match 'E': 1 + dp[4][2] = 3)+---+---+---+---+---+Result: LCS length = 3 ('ACE')

03Levenshtein Edit Distance: Insert, Delete, Replace

Edit Distance measures the minimum number of single-character edits (insertions, deletions, or substitutions) required to transform word1 into word2. It powers spell checkers, autocomplete suggestions, and speech recognition correction.

Let dp[i][j] be the edit distance between word1[0..i-1] and word2[0..j-1]:

1. Base cases: dp[i][0] = i (delete all i characters), dp[0][j] = j (insert all j characters).

2. If word1[i-1] == word2[j-1]: dp[i][j] = dp[i-1][j-1] (no cost).

3. If characters differ, take the minimum of three operations plus 1 cost: dp[i][j] = 1 + min(dp[i-1][j] (Delete), dp[i][j-1] (Insert), dp[i-1][j-1] (Replace)).

example.js☕Java
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

04Space Optimization: Rolling Arrays

In production services matching long DNA sequences or comparing 50,000-line source code files, allocating an (m x n) integer matrix requires hundreds of megabytes of heap memory, triggering GC pressure.

Observing the state transitions reveals that computing dp[i][j] depends ONLY on the current row (dp[i]) and the previous row (dp[i-1]). Elements from two rows prior are never accessed again.

By replacing the full 2D matrix with two 1D arrays of size min(m, n) (prevRow and currRow), memory complexity drops from quadratic O(m * n) to linear O(min(m, n)), while preserving O(m * n) runtime.

05Production Architecture & Engineering Trade-Offs

Dynamic programming solves complex optimization problems by decomposing them into overlapping subproblems and enforcing optimal substructure. However, inexperienced engineers frequently struggle with state-space explosion: defining state dimensions that require excessive memory or state transitions that duplicate computations.

In production applications—such as continuous resource scheduling, query optimization in database planners, and automated financial portfolio rebalancing—space optimization is critical. By recognizing that state transitions often depend only on the immediate previous time step or row, engineers routinely optimize memory consumption from quadratic O(m * n) down to linear O(n) using rolling buffers.

LET IT CLICK

The ideas worth keeping.

  • LCS and Edit Distance use 2D DP matrices to systematically solve optimal string alignment.
  • Backtracking from dp[m][n] to dp[0][0] reconstructs the exact diff operations.
  • Rolling two-row buffers compress space complexity from O(m * n) to linear O(min(m, n)).
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Type and test your code right here in the interactive workspace. Run your solution, check the output, and compare with the worked guide when ready.

01

Exercise 1: Compute the Levenshtein edit distance between

Compute the Levenshtein edit distance between 'horse' and 'ros' step-by-step.

your_turn_1.java☕Java
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.javaJava
// Initial: 'horse'// 1. Replace 'h' with 'r': 'rorse' (cost 1)// 2. Delete 'r': 'rose' (cost 1)// 3. Delete 'e': 'ros' (cost 1)// Total Edit Distance = 3

Find the shortest combination of insert, delete, and replace operations.

02

Exercise 2: How can you reconstruct the actual characters

How can you reconstruct the actual characters forming the Longest Common Subsequence from the completed dp matrix?

your_turn_2.java☕Java
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.javaJava
// Start at dp[m][n] and backtrack toward dp[0][0]:// 1. If text1[i-1] == text2[j-1], this character was part of the LCS://    append text1[i-1] to result, and move diagonally to dp[i-1][j-1].// 2. Else if dp[i-1][j] >= dp[i][j-1], move up to dp[i-1][j].// 3. Else move left to dp[i][j-1].// Finally, reverse the accumulated result string.

Trace back from (m, n): when characters match, step diagonally up-left.

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01What is the recurrence relation for LCS when text1[i-1] == text2[j-1]?
02How can the space complexity of 2D DP algorithms like LCS and Edit Distance be optimized?
03Which operation in Edit Distance corresponds to transitioning from dp[i-1][j] to dp[i][j]?
⚡CODING CHALLENGE
🔒Required to Mark Lesson Complete

Exercise 1: Compute the Levenshtein edit distance between

Compute the Levenshtein edit distance between 'horse' and 'ros' step-by-step.

EXPECTED OUTPUT
Build successful. (Java 15)
[Process exited normally]
Main.javaJava
Ctrl + ↵
Execution Console
Click "Run & Verify" (or press Ctrl + Enter) to test your code against the challenge.

Keep exploring.

The official references behind this lesson, when you want a second angle or the full details.

One lesson closer.

Reading is a start. Trying it yourself makes the connection.

Solve the hands-on coding challenge in the knowledge section to verify your code and unlock lesson completion.