Skip to content
Merged
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
Expand Up @@ -29,20 +29,20 @@ public static String longestCommonSubstring(final String a, final String b) {
return "";
}

int[][] dp = new int[a.length() + 1][b.length() + 1];
int[] dp = new int[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++) {
for (int j = b.length(); j >= 1; 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];
dp[j] = dp[j - 1] + 1;
if (dp[j] > maxLength) {
maxLength = dp[j];
endIndex = i;
}
} else {
dp[i][j] = 0;
dp[j] = 0;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// author: Vraj Prajapati @Rosander0

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

import java.time.Duration;
import org.junit.jupiter.api.Test;

public class LongestCommonSubstringTest {
Expand Down Expand Up @@ -33,4 +35,97 @@ public void testMultipleMatchesFirstLongest() {
// Keeps the first matched longest substring when lengths are tied
assertEquals("abc", LongestCommonSubstring.longestCommonSubstring("abcXdef", "abcYdef"));
}

// NEW

@Test
public void testSpacesAndSpecialCharacters() {
assertEquals(" Hello World! ", LongestCommonSubstring.longestCommonSubstring("123 Hello World! 456", "ABC Hello World! XYZ"));
assertEquals("@#$%^", LongestCommonSubstring.longestCommonSubstring("test@#$%^123", "abc@#$%^xyz"));
}

@Test
public void testCoincidenceAtBoundaries() {
// Match at the beginning
assertEquals("PREFIX_", LongestCommonSubstring.longestCommonSubstring("PREFIX_12345", "PREFIX_67890"));
// Match at the end
assertEquals("_SUFFIX", LongestCommonSubstring.longestCommonSubstring("12345_SUFFIX", "67890_SUFFIX"));
}

@Test
public void testRepeatedPatterns() {
assertEquals("anabanana", LongestCommonSubstring.longestCommonSubstring("bananabanana", "anabanana"));
}

@Test
public void testLargeInputsPerformanceAndTimeout() {
// Generate two 3,000-character strings containing a common substring in the middle
int size = 3000;
StringBuilder sb1 = new StringBuilder(size);
StringBuilder sb2 = new StringBuilder(size);

for (int i = 0; i < 1000; i++) {
sb1.append('A');
sb2.append('B');
}

String commonPart = "COMMON_LONG_SUBSTRING_TEST_1234567890";
sb1.append(commonPart);
sb2.append(commonPart);

for (int i = 0; i < 1500; i++) {
sb1.append('X');
sb2.append('Y');
}

// Verify that the algorithm completes within 2 seconds
assertTimeoutPreemptively(Duration.ofSeconds(2), () -> {
String result = LongestCommonSubstring.longestCommonSubstring(sb1.toString(), sb2.toString());
assertEquals(commonPart, result);
});
}

@Test
public void testVeryLargeInputsPerformance() {
// Generate two very large strings (4,000 characters each)
int size = 4000;
StringBuilder sb1 = new StringBuilder(size);
StringBuilder sb2 = new StringBuilder(size);

for (int i = 0; i < size; i++) {
sb1.append('A');
sb2.append('B');
}

assertTimeoutPreemptively(Duration.ofSeconds(2), () -> { assertEquals("", LongestCommonSubstring.longestCommonSubstring(sb1.toString(), sb2.toString())); });
}

@Test
public void testCaseSensitivityAndUnicode() {
// Case sensitivity test
assertEquals("ABC", LongestCommonSubstring.longestCommonSubstring("ABCdef", "123ABCxyz"));
assertEquals("", LongestCommonSubstring.longestCommonSubstring("abc", "ABC"));

// Full substring containment
assertEquals("inside", LongestCommonSubstring.longestCommonSubstring("inside", "text_inside_here"));

// Unicode characters
assertEquals("_áéíóú_", LongestCommonSubstring.longestCommonSubstring("hola_áéíóú_mundo", "test_áéíóú_abc"));
}

@Test
public void testWhitespaceAndControlCharacters() {
// Test with newlines and tabs
assertEquals("\t\n", LongestCommonSubstring.longestCommonSubstring("start\t\nend", "begin\t\nfinish"));

// Test with multiple consecutive spaces
assertEquals(" ", LongestCommonSubstring.longestCommonSubstring("a b", "x y"));
}

@Test
public void testOverlappingSubstrings() {
// Test overlapping matches like "AAAA" in "AAAAA" vs "AAAA"
assertEquals("AAAA", LongestCommonSubstring.longestCommonSubstring("AAAAA", "AAAA"));
assertEquals("ABAB", LongestCommonSubstring.longestCommonSubstring("ABABAB", "CABAB"));
}
}
Loading