Skip to content

Commit 0388455

Browse files
authored
Add LongestCommonSubstring Implementation (#7464)
feat: add LongestCommonSubstring implementation
1 parent 6fbbc94 commit 0388455

2 files changed

Lines changed: 91 additions & 0 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.thealgorithms.strings;
2+
3+
/**
4+
* Longest Common Substring finds the longest string that is a
5+
* contiguous substring of two input strings.
6+
* Example: "abcdef" and "zcdemf" -> "cde"
7+
*
8+
* @see <a href="https://en.wikipedia.org/wiki/Longest_common_substring">
9+
* Wikipedia: Longest Common Substring</a>
10+
*
11+
* author: Vraj Prajapati @Rosander0
12+
*/
13+
public final class LongestCommonSubstring {
14+
15+
private LongestCommonSubstring() {
16+
// Utility class
17+
}
18+
19+
/**
20+
* Finds the longest common substring of two strings.
21+
*
22+
* @param a First input string
23+
* @param b Second input string
24+
* @return The longest common substring, or empty string if none exists.
25+
* If multiple substrings share the maximum length, the first one found is returned.
26+
*/
27+
public static String longestCommonSubstring(final String a, final String b) {
28+
if (a == null || b == null || a.isEmpty() || b.isEmpty()) {
29+
return "";
30+
}
31+
32+
int[][] dp = new int[a.length() + 1][b.length() + 1];
33+
int maxLength = 0;
34+
int endIndex = 0;
35+
36+
for (int i = 1; i <= a.length(); i++) {
37+
for (int j = 1; j <= b.length(); j++) {
38+
if (a.charAt(i - 1) == b.charAt(j - 1)) {
39+
dp[i][j] = dp[i - 1][j - 1] + 1;
40+
if (dp[i][j] > maxLength) {
41+
maxLength = dp[i][j];
42+
endIndex = i;
43+
}
44+
} else {
45+
dp[i][j] = 0;
46+
}
47+
}
48+
}
49+
50+
if (maxLength == 0) {
51+
return "";
52+
}
53+
return a.substring(endIndex - maxLength, endIndex);
54+
}
55+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.thealgorithms.strings;
2+
// author: Vraj Prajapati @Rosander0
3+
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
public class LongestCommonSubstringTest {
9+
10+
@Test
11+
public void testNullOrEmptyInputs() {
12+
assertEquals("", LongestCommonSubstring.longestCommonSubstring(null, "abc"));
13+
assertEquals("", LongestCommonSubstring.longestCommonSubstring("abc", null));
14+
assertEquals("", LongestCommonSubstring.longestCommonSubstring("", "abc"));
15+
assertEquals("", LongestCommonSubstring.longestCommonSubstring("abc", ""));
16+
}
17+
18+
@Test
19+
public void testNormalSubstrings() {
20+
assertEquals("cde", LongestCommonSubstring.longestCommonSubstring("abcdef", "zcdemf"));
21+
assertEquals("abc", LongestCommonSubstring.longestCommonSubstring("abc", "abc"));
22+
assertEquals("cdef", LongestCommonSubstring.longestCommonSubstring("abcdef", "cdefgh"));
23+
}
24+
25+
@Test
26+
public void testSingleCharacterAndNoMatch() {
27+
assertEquals("a", LongestCommonSubstring.longestCommonSubstring("a", "a"));
28+
assertEquals("", LongestCommonSubstring.longestCommonSubstring("abc", "xyz"));
29+
}
30+
31+
@Test
32+
public void testMultipleMatchesFirstLongest() {
33+
// Keeps the first matched longest substring when lengths are tied
34+
assertEquals("abc", LongestCommonSubstring.longestCommonSubstring("abcXdef", "abcYdef"));
35+
}
36+
}

0 commit comments

Comments
 (0)