From 9b9bfd7f52fef56120e3a53bfc3b0501c83805ad Mon Sep 17 00:00:00 2001 From: Rosander0 Date: Wed, 10 Jun 2026 18:30:04 +0530 Subject: [PATCH] feat: add LongestCommonSubstring implementation --- pom.xml | 2 +- .../strings/LongestCommonSubstring.java | 55 +++++++++++++++++++ .../strings/LongestCommonSubstringTest.java | 36 ++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/thealgorithms/strings/LongestCommonSubstring.java create mode 100644 src/test/java/com/thealgorithms/strings/LongestCommonSubstringTest.java diff --git a/pom.xml b/pom.xml index 6edd36f446d8..e54b83399e9f 100644 --- a/pom.xml +++ b/pom.xml @@ -119,7 +119,7 @@ com.github.spotbugs spotbugs-maven-plugin - 4.9.8.3 + 4.10.2.0 spotbugs-exclude.xml true diff --git a/src/main/java/com/thealgorithms/strings/LongestCommonSubstring.java b/src/main/java/com/thealgorithms/strings/LongestCommonSubstring.java new file mode 100644 index 000000000000..b2190316aff2 --- /dev/null +++ b/src/main/java/com/thealgorithms/strings/LongestCommonSubstring.java @@ -0,0 +1,55 @@ +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" + * + * @see + * Wikipedia: Longest Common Substring + * + * 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 exists. + * If multiple substrings share the maximum length, the first one found is returned. + */ + 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; + } + } + } + + if (maxLength == 0) { + return ""; + } + return a.substring(endIndex - maxLength, endIndex); + } +} diff --git a/src/test/java/com/thealgorithms/strings/LongestCommonSubstringTest.java b/src/test/java/com/thealgorithms/strings/LongestCommonSubstringTest.java new file mode 100644 index 000000000000..e54abcf2f1f3 --- /dev/null +++ b/src/test/java/com/thealgorithms/strings/LongestCommonSubstringTest.java @@ -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")); + } +}