Skip to content

Commit 34079f0

Browse files
test(dp): add tests for LongestPalindromicSubsequence and remove main… (#7462)
* test(dp): add tests for LongestPalindromicSubsequence and remove main method * fix: formatting and style fixes for clang-format compliance * fix: correct expected values in tests and add missing EOF newline --------- Co-authored-by: Deniz Altunkapan <deniz.altunkapan@outlook.com>
1 parent d792409 commit 34079f0

2 files changed

Lines changed: 82 additions & 44 deletions

File tree

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,42 @@
11
package com.thealgorithms.dynamicprogramming;
22

33
/**
4-
* Algorithm explanation
5-
* https://www.educative.io/edpresso/longest-palindromic-subsequence-algorithm
4+
* Longest Palindromic Subsequence algorithm.
5+
* A palindromic subsequence is a subsequence that reads the same forwards and backwards.
6+
* This implementation finds the longest such subsequence by computing the LCS of the
7+
* original string and its reverse.
8+
*
9+
* @see <a href="https://en.wikipedia.org/wiki/Longest_palindromic_subsequence">Wikipedia</a>
610
*/
711
public final class LongestPalindromicSubsequence {
812
private LongestPalindromicSubsequence() {
913
}
1014

11-
public static void main(String[] args) {
12-
String a = "BBABCBCAB";
13-
String b = "BABCBAB";
14-
15-
String aLPS = lps(a);
16-
String bLPS = lps(b);
17-
18-
System.out.println(a + " => " + aLPS);
19-
System.out.println(b + " => " + bLPS);
20-
}
21-
22-
public static String lps(String original) throws IllegalArgumentException {
23-
StringBuilder reverse = new StringBuilder(original);
24-
reverse = reverse.reverse();
25-
return recursiveLPS(original, reverse.toString());
15+
/**
16+
* Returns the longest palindromic subsequence of the given string.
17+
*
18+
* @param original the input string
19+
* @return the longest palindromic subsequence
20+
* @throws IllegalArgumentException if the input string is null
21+
*/
22+
public static String lps(String original) {
23+
if (original == null) {
24+
throw new IllegalArgumentException("Input string must not be null");
25+
}
26+
String reverse = new StringBuilder(original).reverse().toString();
27+
return recursiveLPS(original, reverse);
2628
}
2729

2830
private static String recursiveLPS(String original, String reverse) {
29-
String bestResult = "";
30-
31-
// no more chars, then return empty
32-
if (original.length() == 0 || reverse.length() == 0) {
33-
bestResult = "";
34-
} else {
35-
// if the last chars match, then remove it from both strings and recur
36-
if (original.charAt(original.length() - 1) == reverse.charAt(reverse.length() - 1)) {
37-
String bestSubResult = recursiveLPS(original.substring(0, original.length() - 1), reverse.substring(0, reverse.length() - 1));
38-
39-
bestResult = reverse.charAt(reverse.length() - 1) + bestSubResult;
40-
} else {
41-
// otherwise (1) ignore the last character of reverse, and recur on original and
42-
// updated reverse again (2) ignore the last character of original and recur on the
43-
// updated original and reverse again then select the best result from these two
44-
// subproblems.
45-
46-
String bestSubResult1 = recursiveLPS(original, reverse.substring(0, reverse.length() - 1));
47-
String bestSubResult2 = recursiveLPS(original.substring(0, original.length() - 1), reverse);
48-
if (bestSubResult1.length() > bestSubResult2.length()) {
49-
bestResult = bestSubResult1;
50-
} else {
51-
bestResult = bestSubResult2;
52-
}
53-
}
31+
if (original.isEmpty() || reverse.isEmpty()) {
32+
return "";
5433
}
55-
56-
return bestResult;
34+
if (original.charAt(original.length() - 1) == reverse.charAt(reverse.length() - 1)) {
35+
String bestSubResult = recursiveLPS(original.substring(0, original.length() - 1), reverse.substring(0, reverse.length() - 1));
36+
return reverse.charAt(reverse.length() - 1) + bestSubResult;
37+
}
38+
String sub1 = recursiveLPS(original, reverse.substring(0, reverse.length() - 1));
39+
String sub2 = recursiveLPS(original.substring(0, original.length() - 1), reverse);
40+
return sub1.length() >= sub2.length() ? sub1 : sub2;
5741
}
5842
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.params.ParameterizedTest;
8+
import org.junit.jupiter.params.provider.CsvSource;
9+
10+
public class LongestPalindromicSubsequenceTest {
11+
12+
@ParameterizedTest
13+
@CsvSource({"BBABCBCAB, BACBCAB", "BABCBAB, BABCBAB", "A, A", "AA, AA", "AB, B"})
14+
void testLpsKnownCases(String input, String expectedLps) {
15+
assertEquals(expectedLps, LongestPalindromicSubsequence.lps(input));
16+
}
17+
18+
@Test
19+
void testLpsEmptyString() {
20+
assertEquals("", LongestPalindromicSubsequence.lps(""));
21+
}
22+
23+
@Test
24+
void testLpsSingleCharacter() {
25+
assertEquals("Z", LongestPalindromicSubsequence.lps("Z"));
26+
}
27+
28+
@Test
29+
void testLpsAllSameCharacters() {
30+
assertEquals("AAAA", LongestPalindromicSubsequence.lps("AAAA"));
31+
}
32+
33+
@Test
34+
void testLpsAlreadyPalindrome() {
35+
assertEquals("RACECAR", LongestPalindromicSubsequence.lps("RACECAR"));
36+
}
37+
38+
@Test
39+
void testLpsNoRepeatingCharacters() {
40+
assertEquals(1, LongestPalindromicSubsequence.lps("ABCDE").length());
41+
}
42+
43+
@Test
44+
void testLpsNullThrowsException() {
45+
assertThrows(IllegalArgumentException.class, () -> { LongestPalindromicSubsequence.lps(null); });
46+
}
47+
48+
@Test
49+
void testLpsResultIsActuallyPalindrome() {
50+
String result = LongestPalindromicSubsequence.lps("BBABCBCAB");
51+
String reversed = new StringBuilder(result).reverse().toString();
52+
assertEquals(result, reversed);
53+
}
54+
}

0 commit comments

Comments
 (0)