Longest Common Substring
The table only reads the row above it, so one row is enough. Overwrite that row in place. Go j from high to low, so that row[j − 1] still holds the row above when we read it. On a match, row[j] = row[j − 1] + 1. On a mismatch, row[j] = 0. The answer is the largest value ever written.
A common run must be contiguous, so on a mismatch the run restarts at 0. Then dp[i][j] is the length of the run that ends exactly at these two letters.
Problem
You get two strings, s1 and s2. Find the length of the longest substring that appears in both strings.
A substring is a run of characters that sit next to each other. A gap is not allowed. Matching is case-sensitive, so Y and y are different letters.
Return the length as a number.
Two strings s1 and s2.
A single number: the length of the longest common substring. It is 0 when the two strings share no letter.
The longest common substring is "CDGH", which has length 4.
Only single letters are shared as a run: "a", "b" and "c" each have length 1. The pair "ab" is in s1, but it is not a run in s2.
Matching is case-sensitive: Y is not y and Z is not z, so nothing is shared.
- • 1 ≤ s1.length, s2.length ≤ 10^3
- • s1 and s2 contain only English letters.
- • Matching is case-sensitive.
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
A subsequence can skip letters, but a substring cannot. Which one does this problem ask for?
- 2.
If the last letters of two prefixes match, how long is the common run that ends there?
- 3.
What should happen to the run when two letters differ? Can the run jump over that gap?
- 4.
Can the longest run end at any pair of positions, or only at the very end of both strings?
- 5.
Do I need the whole table, or only the row just above the one I am filling?
Brute force approach
Better approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Try every pair of start positions and extend the run while the letters match | O(N · M · min(N, M)) | O(1) |
| Better | Fill an (N + 1) × (M + 1) table; a match extends the diagonal cell by one | O(N · M) | O(N · M) |
| Optimal | Keep one row; on a match row[j] = row[j − 1] + 1, on a mismatch 0; read j from high to low | O(N · M) | O(M) |
Why does this belong to this pattern?
- “substring”A run of letters that sit next to each other. A gap means the run starts again from 0.
- “appears in both strings”The run must match in s1 and in s2 at the same time, so we compare pairs of positions, one from each string.
- “longest length”The answer is the largest run that ends at any pair, not the value at the last pair.
This is the anchor of the Common substring family. The rule that changes everything is the reset: on a mismatch the run goes to 0, not to the best value of the cell above or to the left. That reset is what separates it from the subsequence problem, LCS, which carries the best value across a gap. Maximum Length of Repeated Subarray applies the same rule to integer arrays.
Don't make this mistake
The max rule computes the longest common subsequence, which may skip letters. On the dry run (ABCDGH and ACDGHR) this rule gives 5, the length of the subsequence ACDGH with gaps. The longest common substring is 4 (CDGH), because a substring cannot skip a letter.
The longest run can end anywhere. On ABCDGH and ACDGHR the last pair is H and R, which differ, so dp[6][6] = 0. The wrong code returns 0 instead of 4.
Going low to high, row[j − 1] has already been overwritten with this row's value, so the run grows through the wrong letters. On the dry run the answer becomes 1 instead of 4.
Want to implement this?
Write it yourself on GeeksforGeeks, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like DP — Strings translate into production architectures and low-level memory mechanics.
Foundations: Object-Oriented Principles in C++23
Class invariants, pure virtual interfaces, and RAII smart pointers.
Food Delivery System (Zomato Architecture)
Real-world machine coding application of algorithms and design patterns.
Pointers vs References Deep Dive
Pointer arithmetic and memory layout under the hood.
Virtual Method Table (vtable) & Memory Layout
Polymorphism, vptr overhead, and multiple inheritance in memory.