|
1 | 1 | package com.thealgorithms.strings;
|
2 | 2 |
|
3 |
| -/** |
4 |
| - * Wikipedia: https://en.wikipedia.org/wiki/Palindrome |
5 |
| - */ |
6 |
| -final class Palindrome { |
| 3 | +import org.junit.jupiter.api.Test; |
| 4 | +import static org.junit.jupiter.api.Assertions.*; |
| 5 | + |
| 6 | +public final class Palindrome { |
| 7 | + |
7 | 8 | private Palindrome() {
|
8 | 9 | }
|
9 | 10 |
|
10 | 11 | /**
|
11 |
| - * Check if a string is palindrome string or not using String Builder |
| 12 | + * Check if a string is palindrome or not using StringBuilder. |
12 | 13 | *
|
13 | 14 | * @param s a string to check
|
14 |
| - * @return {@code true} if given string is palindrome, otherwise |
15 |
| - * {@code false} |
| 15 | + * @return {@code true} if given string is palindrome, otherwise {@code false} |
16 | 16 | */
|
17 | 17 | public static boolean isPalindrome(String s) {
|
18 |
| - return ((s == null || s.length() <= 1) || s.equals(new StringBuilder(s).reverse().toString())); |
| 18 | + if (s == null || s.length() <= 1) { |
| 19 | + return true; |
| 20 | + } |
| 21 | + String cleanedString = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); |
| 22 | + return cleanedString.equals(new StringBuilder(cleanedString).reverse().toString()); |
19 | 23 | }
|
20 | 24 |
|
21 | 25 | /**
|
22 |
| - * Check if a string is palindrome string or not using recursion |
| 26 | + * Check if a string is palindrome using optimized recursion (pointer-based). |
23 | 27 | *
|
24 | 28 | * @param s a string to check
|
25 |
| - * @return {@code true} if given string is palindrome, otherwise |
26 |
| - * {@code false} |
| 29 | + * @return {@code true} if given string is palindrome, otherwise {@code false} |
27 | 30 | */
|
28 | 31 | public static boolean isPalindromeRecursion(String s) {
|
29 |
| - if (s == null || s.length() <= 1) { |
| 32 | + if (s == null) { |
30 | 33 | return true;
|
31 | 34 | }
|
| 35 | + String cleanedString = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); |
| 36 | + return isPalindromeRecursion(cleanedString, 0, cleanedString.length() - 1); |
| 37 | + } |
32 | 38 |
|
33 |
| - if (s.charAt(0) != s.charAt(s.length() - 1)) { |
| 39 | + private static boolean isPalindromeRecursion(String s, int left, int right) { |
| 40 | + if (left >= right) { |
| 41 | + return true; |
| 42 | + } |
| 43 | + if (s.charAt(left) != s.charAt(right)) { |
34 | 44 | return false;
|
35 | 45 | }
|
36 |
| - |
37 |
| - return isPalindromeRecursion(s.substring(1, s.length() - 1)); |
| 46 | + return isPalindromeRecursion(s, left + 1, right - 1); |
38 | 47 | }
|
39 | 48 |
|
40 | 49 | /**
|
41 |
| - * Check if a string is palindrome string or not using two pointer technique |
| 50 | + * Check if a string is palindrome using the two-pointer technique. |
42 | 51 | *
|
43 | 52 | * @param s a string to check
|
44 |
| - * @return {@code true} if given string is palindrome, otherwise |
45 |
| - * {@code false} |
| 53 | + * @return {@code true} if given string is palindrome, otherwise {@code false} |
46 | 54 | */
|
47 | 55 | public static boolean isPalindromeTwoPointer(String s) {
|
48 | 56 | if (s == null || s.length() <= 1) {
|
49 | 57 | return true;
|
50 | 58 | }
|
51 |
| - for (int i = 0, j = s.length() - 1; i < j; ++i, --j) { |
52 |
| - if (s.charAt(i) != s.charAt(j)) { |
| 59 | + String cleanedString = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); |
| 60 | + int left = 0; |
| 61 | + int right = cleanedString.length() - 1; |
| 62 | + while (left < right) { |
| 63 | + if (cleanedString.charAt(left) != cleanedString.charAt(right)) { |
53 | 64 | return false;
|
54 | 65 | }
|
| 66 | + left++; |
| 67 | + right--; |
55 | 68 | }
|
56 | 69 | return true;
|
57 | 70 | }
|
| 71 | + |
| 72 | + /** |
| 73 | + * JUnit Test Cases for the Palindrome methods |
| 74 | + */ |
| 75 | + public static class PalindromeTest { |
| 76 | + |
| 77 | + @Test |
| 78 | + void testIsPalindrome() { |
| 79 | + assertTrue(Palindrome.isPalindrome("madam")); |
| 80 | + assertFalse(Palindrome.isPalindrome("hello")); |
| 81 | + assertTrue(Palindrome.isPalindrome("A man, a plan, a canal: Panama")); |
| 82 | + assertTrue(Palindrome.isPalindrome("")); |
| 83 | + assertTrue(Palindrome.isPalindrome("a")); |
| 84 | + } |
| 85 | + |
| 86 | + @Test |
| 87 | + void testIsPalindromeRecursion() { |
| 88 | + assertTrue(Palindrome.isPalindromeRecursion("racecar")); |
| 89 | + assertFalse(Palindrome.isPalindromeRecursion("world")); |
| 90 | + assertTrue(Palindrome.isPalindromeRecursion("A man, a plan, a canal, Panama")); |
| 91 | + assertTrue(Palindrome.isPalindromeRecursion("a")); |
| 92 | + assertTrue(Palindrome.isPalindromeRecursion(null)); |
| 93 | + } |
| 94 | + |
| 95 | + @Test |
| 96 | + void testIsPalindromeTwoPointer() { |
| 97 | + assertTrue(Palindrome.isPalindromeTwoPointer("madam")); |
| 98 | + assertFalse(Palindrome.isPalindromeTwoPointer("hello")); |
| 99 | + assertTrue(Palindrome.isPalindromeTwoPointer("A man, a plan, a canal: Panama")); |
| 100 | + assertTrue(Palindrome.isPalindromeTwoPointer("a")); |
| 101 | + assertTrue(Palindrome.isPalindromeTwoPointer(null)); |
| 102 | + } |
| 103 | + } |
58 | 104 | }
|
0 commit comments