![]() |
VOOZH | about |
Given two strings s1 and s2, find the length of the longest common substring. A substring is a sequence of characters that appears contiguously in a string.
Example:
Input: s1 = "GeeksforGeeks", s2 = "GeeksQuiz"
Output : 5
Explanation: The longest common substring is "Geeks" and is of length 5.Input: s1 = "abcdxyz", s2 = "xyzabcd"
Output : 4
Explanation: The longest common substring is "abcd" and is of length 4.Input: s1 = "abc", s2 = ""
Output : 0
Table of Content
The idea is to consider every pair of indexes (i, j) and find the longest common substring ending at i in s1 and j in s2. In other words, we find the longest common suffix ending at every pair(i, j). At the end, we return length of the max of all longest common suffixes. To find length of the common suffix ending at i and j, we recursively use the lengths of the longest common suffixes ending at (i-1) and (j-1).
Length of the Longest Common Substring = Max of lengths of all Longest Common Suffixes
Length of the Longest Common Suffix Ending at (i, j) = Length of Longest Common Suffix Ending at (i-1, j-1) + 1 if s1[i] == s2[j], else 0
5
From the recursive approach we can observe that the same (i, j) states are solved repeatedly while computing common suffixes, leading to overlapping subproblems. So,
- Recursive Logic to Tabulation: We replace expensive recursive calls with a DP table, where each cell [i, j] stores the length of the common suffix ending at s1[i-1] and s2[j-1].
- The Match Rule: If characters at s1[i] and s2[j] match, we look at the diagonal neighbor [i-1, j-1] and add 1 to that value to extend the "chain."
- The Reset Rule: If they don't match, we set the cell to 0, effectively breaking the current substring chain.
- Global Maximum: Since the longest common substring can end anywhere, we track the maximum value encountered across the entire table
Say the strings are S1 = "ABCD" and S2 = "ACDG", Follow below :
5
From the DP state transition, we can observe that,
Since each state dp[i][j] depends only on the diagonal value from the previous row, dp[i−1][j−1], we do not need to store the entire 2D DP table. Keeping only the previous row is sufficient, which allows us to optimize the space from O(m×n) to O(n).
We keep a prev[] array for the last row and build a curr[] array for the current row.
When the characters match, we extend the substring using prev[j−1]; when they don’t, we reset the length to 0.
After completing a row, curr becomes the new prev.
This keeps the logic exactly the same while using only a linear-size array instead of the full table.
5