Longest Common Substring in DSA Java - Time & Space Complexity
We want to understand how the time needed to find the longest common substring grows as the input strings get longer.
How does the work increase when the strings become bigger?
Analyze the time complexity of the following code snippet.
public int longestCommonSubstring(String s1, String s2) {
int maxLen = 0;
int[][] dp = new int[s1.length() + 1][s2.length() + 1];
for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
maxLen = Math.max(maxLen, dp[i][j]);
} else {
dp[i][j] = 0;
}
}
}
return maxLen;
}
This code finds the length of the longest substring that appears in both input strings by building a table of matching character lengths.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops comparing characters of both strings.
- How many times: Outer loop runs for length of first string (n), inner loop runs for length of second string (m), so total n * m times.
As the strings get longer, the number of comparisons grows by multiplying their lengths.
| Input Size (n = m) | Approx. Operations |
|---|---|
| 10 | 100 |
| 100 | 10,000 |
| 1000 | 1,000,000 |
Pattern observation: Doubling the length roughly quadruples the work, showing a square growth pattern.
Time Complexity: O(n * m)
This means the time needed grows proportionally to the product of the lengths of the two strings.
[X] Wrong: "The algorithm runs in linear time because it just loops through the strings once."
[OK] Correct: The algorithm uses two nested loops, so it compares each character of the first string with each character of the second, making the work multiply, not just add.
Understanding this time complexity helps you explain how dynamic programming solutions scale and why nested loops matter, a skill useful in many coding challenges.
"What if we used a suffix tree instead of dynamic programming? How would the time complexity change?"
Practice
s1 and s2?Solution
Step 1: Understand the problem definition
The Longest Common Substring problem looks for the longest continuous sequence of characters that appear exactly the same and consecutively in both strings.Step 2: Compare options with the definition
The longest sequence of characters that appear consecutively in both strings correctly describes this as a consecutive sequence. Options B and C describe subsequences or counts, not substrings. The longest sequence of characters that appear only in the first string is unrelated.Final Answer:
The longest sequence of characters that appear consecutively in both strings -> Option DQuick Check:
Longest Common Substring = Consecutive matching sequence [OK]
- Confusing substring with subsequence
- Thinking order does not matter
- Counting total common characters instead
dp for Longest Common Substring of size m+1 by n+1?Solution
Step 1: Understand array size for DP table
For Longest Common Substring, we use a DP table of size (m+1) x (n+1) to handle empty prefixes of both strings.Step 2: Check each option's correctness
int[][] dp = new int[m+1][n+1]; correctly creates a 2D array with dimensions m+1 and n+1. int[][] dp = new int[m][n]; misses the +1, int dp[][] = new int[m-1][n-1]; uses m-1 and n-1 which is invalid, and int dp[][] = new int[m+1]; creates a 1D array.Final Answer:
int[][] dp = new int[m+1][n+1]; -> Option BQuick Check:
DP array size = (m+1) x (n+1) [OK]
- Using wrong array dimensions without +1
- Declaring 1D array instead of 2D
- Using negative or zero sizes
String s1 = "abcdxyz";
String s2 = "xyzabcd";
int m = s1.length();
int n = s2.length();
int[][] dp = new int[m+1][n+1];
int maxLen = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s1.charAt(i-1) == s2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + 1;
maxLen = Math.max(maxLen, dp[i][j]);
} else {
dp[i][j] = 0;
}
}
}
System.out.println(maxLen);Solution
Step 1: Understand the strings and DP logic
s1 = "abcdxyz", s2 = "xyzabcd". The code finds the longest common substring length using DP.Step 2: Trace the longest common substring
The longest common substring is "abcd" which appears consecutively in both strings (s1[0-3], s2[3-6]). Its length is 4. "xyz" appears consecutively with length 3.Final Answer:
4 -> Option AQuick Check:
Longest common substring length = 4 [OK]
- Confusing substring with subsequence
- Missing the diagonal match for 'abcd'
- Ignoring DP reset to zero on mismatch
String s1 = "abcde";
String s2 = "abfde";
int m = s1.length();
int n = s2.length();
int[][] dp = new int[m+1][n+1];
int maxLen = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s1.charAt(i) == s2.charAt(j)) {
dp[i][j] = dp[i-1][j-1] + 1;
maxLen = Math.max(maxLen, dp[i][j]);
} else {
dp[i][j] = 0;
}
}
}
System.out.println(maxLen);Solution
Step 1: Check charAt indices usage
In Java, string indices start at 0, but the loop runs i and j from 1 to length. Using s1.charAt(i) and s2.charAt(j) causes index out of bounds when i or j equals length.Step 2: Correct index usage
Indices should be i-1 and j-1 to access characters correctly inside the loop.Final Answer:
Index out of bounds due to incorrect charAt indices -> Option CQuick Check:
charAt indices must be i-1, j-1 [OK]
- Using i and j directly as string indices
- Not adjusting for zero-based indexing
- Ignoring array bounds errors
s1 = "banana" and s2 = "ananas", which of the following Java methods correctly returns the longest common substring length?Solution
Step 1: Recall DP approach for Longest Common Substring
We use a 2D DP array where dp[i][j] stores length of longest common substring ending at s1[i-1] and s2[j-1]. If characters match, dp[i][j] = dp[i-1][j-1] + 1; else 0.Step 2: Evaluate each option
Use nested loops with DP, update dp[i][j] = dp[i-1][j-1] + 1 if chars match, else 0, track maxLen correctly describes this approach. Options A, C, and D describe incorrect logic that does not reset on mismatch or use wrong indices.Final Answer:
Use nested loops with DP, update dp[i][j] = dp[i-1][j-1] + 1 if chars match, else 0, track maxLen -> Option AQuick Check:
DP update with reset on mismatch = correct method [OK]
- Not resetting DP cell to zero on mismatch
- Using wrong DP update formula
- Counting subsequence instead of substring
Ready to prove it?
Pass the test and this pattern moves unknown
