Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.thealgorithms.strings;

/**
* Longest Common Substring finds the longest string that is a
* contiguous substring of two input strings.
* Example: "abcdef" and "zcdemf" -> "cde"
*
* author: Vraj Prajapati @Rosander0
*/
public final class LongestCommonSubstring {

private LongestCommonSubstring() {
// Utility class
}

/**
* Finds the longest common substring of two strings.
*
* @param a First input string
* @param b Second input string
* @return The longest common substring, or empty string if none found
*/
public static String longestCommonSubstring(final String a, final String b) {
if (a == null || b == null || a.isEmpty() || b.isEmpty()) {
return "";
}

int[][] dp = new int[a.length() + 1][b.length() + 1];
int maxLength = 0;
int endIndex = 0;

for (int i = 1; i <= a.length(); i++) {
for (int j = 1; j <= b.length(); j++) {
if (a.charAt(i - 1) == b.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i][j] > maxLength) {
maxLength = dp[i][j];
endIndex = i;
}
} else {
dp[i][j] = 0;
}
}
}
return a.substring(endIndex - maxLength, endIndex);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.thealgorithms.strings;
// author: Vraj Prajapati @Rosander0

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class LongestCommonSubstringTest {

@Test
public void testNullOrEmptyInputs() {
assertEquals("", LongestCommonSubstring.longestCommonSubstring(null, "abc"));
assertEquals("", LongestCommonSubstring.longestCommonSubstring("abc", null));
assertEquals("", LongestCommonSubstring.longestCommonSubstring("", "abc"));
assertEquals("", LongestCommonSubstring.longestCommonSubstring("abc", ""));
}

@Test
public void testNormalSubstrings() {
assertEquals("cde", LongestCommonSubstring.longestCommonSubstring("abcdef", "zcdemf"));
assertEquals("abc", LongestCommonSubstring.longestCommonSubstring("abc", "abc"));
assertEquals("cdef", LongestCommonSubstring.longestCommonSubstring("abcdef", "cdefgh"));
}

@Test
public void testSingleCharacterAndNoMatch() {
assertEquals("a", LongestCommonSubstring.longestCommonSubstring("a", "a"));
assertEquals("", LongestCommonSubstring.longestCommonSubstring("abc", "xyz"));
}

@Test
public void testMultipleMatchesFirstLongest() {
// Keeps the first matched longest substring when lengths are tied
assertEquals("abc", LongestCommonSubstring.longestCommonSubstring("abcXdef", "abcYdef"));
}
}
Loading