diff --git a/java-strings/src/main/java/com/baeldung/string/SubstringPalindrome.java b/java-strings/src/main/java/com/baeldung/string/SubstringPalindrome.java new file mode 100644 index 0000000000..688bf43b3c --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/SubstringPalindrome.java @@ -0,0 +1,90 @@ +package com.baeldung.string; + +import java.util.HashSet; +import java.util.Set; + +public class SubstringPalindrome { + + public Set findAllPalindromesUsingCenter(String input) { + final Set palindromes = new HashSet<>(); + if (input == null || input.isEmpty()) { + return palindromes; + } + if (input.length() == 1) { + palindromes.add(input); + return palindromes; + } + for (int i = 0; i < input.length(); i++) { + palindromes.addAll(findPalindromes(input, i, i + 1)); + palindromes.addAll(findPalindromes(input, i, i)); + } + return palindromes; + } + + private Set findPalindromes(String input, int low, int high) { + Set result = new HashSet<>(); + while (low >= 0 && high < input.length() && input.charAt(low) == input.charAt(high)) { + result.add(input.substring(low, high + 1)); + low--; + high++; + } + return result; + } + + public Set findAllPalindromesUsingBruteForceApproach(String input) { + Set palindromes = new HashSet<>(); + if (input == null || input.isEmpty()) { + return palindromes; + } + if (input.length() == 1) { + palindromes.add(input); + return palindromes; + } + for (int i = 0; i < input.length(); i++) { + for (int j = i + 1; j <= input.length(); j++) + if (isPalindrome(input.substring(i, j))) { + palindromes.add(input.substring(i, j)); + } + } + return palindromes; + } + + private boolean isPalindrome(String input) { + StringBuilder plain = new StringBuilder(input); + StringBuilder reverse = plain.reverse(); + return (reverse.toString()).equals(input); + } + + public Set findAllPalindromesUsingManachersAlgorithm(String input) { + Set palindromes = new HashSet<>(); + String formattedInput = "@" + input + "#"; + char inputCharArr[] = formattedInput.toCharArray(); + int max; + int radius[][] = new int[2][input.length() + 1]; + for (int j = 0; j <= 1; j++) { + radius[j][0] = max = 0; + int i = 1; + while (i <= input.length()) { + palindromes.add(Character.toString(inputCharArr[i])); + while (inputCharArr[i - max - 1] == inputCharArr[i + j + max]) + max++; + radius[j][i] = max; + int k = 1; + while ((radius[j][i - k] != max - k) && (k < max)) { + radius[j][i + k] = Math.min(radius[j][i - k], max - k); + k++; + } + max = Math.max(max - k, 0); + i += k; + } + } + for (int i = 1; i <= input.length(); i++) { + for (int j = 0; j <= 1; j++) { + for (max = radius[j][i]; max > 0; max--) { + palindromes.add(input.substring(i - max - 1, max + j + i - 1)); + } + } + } + return palindromes; + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/SubstringPalindromeUnitTest.java b/java-strings/src/test/java/com/baeldung/string/SubstringPalindromeUnitTest.java new file mode 100644 index 0000000000..b18a8d4a5f --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/SubstringPalindromeUnitTest.java @@ -0,0 +1,83 @@ +package com.baeldung.string; + +import static org.junit.Assert.assertEquals; +import java.util.HashSet; +import java.util.Set; +import org.junit.Test; + +public class SubstringPalindromeUnitTest { + + private static final String INPUT_BUBBLE = "bubble"; + private static final String INPUT_CIVIC = "civic"; + private static final String INPUT_INDEED = "indeed"; + private static final String INPUT_ABABAC = "ababac"; + + Set EXPECTED_PALINDROME_BUBBLE = new HashSet() { + { + add("b"); + add("u"); + add("l"); + add("e"); + add("bb"); + add("bub"); + } + }; + + Set EXPECTED_PALINDROME_CIVIC = new HashSet() { + { + add("civic"); + add("ivi"); + add("i"); + add("c"); + add("v"); + } + }; + + Set EXPECTED_PALINDROME_INDEED = new HashSet() { + { + add("i"); + add("n"); + add("d"); + add("e"); + add("ee"); + add("deed"); + } + }; + + Set EXPECTED_PALINDROME_ABABAC = new HashSet() { + { + add("a"); + add("b"); + add("c"); + add("aba"); + add("bab"); + add("ababa"); + } + }; + + private SubstringPalindrome palindrome = new SubstringPalindrome(); + + @Test + public void whenUsingManachersAlgorithm_thenFindsAllPalindromes() { + assertEquals(EXPECTED_PALINDROME_BUBBLE, palindrome.findAllPalindromesUsingManachersAlgorithm(INPUT_BUBBLE)); + assertEquals(EXPECTED_PALINDROME_INDEED, palindrome.findAllPalindromesUsingManachersAlgorithm(INPUT_INDEED)); + assertEquals(EXPECTED_PALINDROME_CIVIC, palindrome.findAllPalindromesUsingManachersAlgorithm(INPUT_CIVIC)); + assertEquals(EXPECTED_PALINDROME_ABABAC, palindrome.findAllPalindromesUsingManachersAlgorithm(INPUT_ABABAC)); + } + + @Test + public void whenUsingCenterApproach_thenFindsAllPalindromes() { + assertEquals(EXPECTED_PALINDROME_BUBBLE, palindrome.findAllPalindromesUsingCenter(INPUT_BUBBLE)); + assertEquals(EXPECTED_PALINDROME_INDEED, palindrome.findAllPalindromesUsingCenter(INPUT_INDEED)); + assertEquals(EXPECTED_PALINDROME_CIVIC, palindrome.findAllPalindromesUsingCenter(INPUT_CIVIC)); + assertEquals(EXPECTED_PALINDROME_ABABAC, palindrome.findAllPalindromesUsingCenter(INPUT_ABABAC)); + } + + @Test + public void whenUsingBruteForceApproach_thenFindsAllPalindromes() { + assertEquals(EXPECTED_PALINDROME_BUBBLE, palindrome.findAllPalindromesUsingBruteForceApproach(INPUT_BUBBLE)); + assertEquals(EXPECTED_PALINDROME_INDEED, palindrome.findAllPalindromesUsingBruteForceApproach(INPUT_INDEED)); + assertEquals(EXPECTED_PALINDROME_CIVIC, palindrome.findAllPalindromesUsingBruteForceApproach(INPUT_CIVIC)); + assertEquals(EXPECTED_PALINDROME_ABABAC, palindrome.findAllPalindromesUsingBruteForceApproach(INPUT_ABABAC)); + } +}