Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,34 @@
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