Palindrome Program in Java: Check Strings and Numbers

Write a palindrome program in Java for strings, phrases and numbers with two pointers, StringBuilder, recursion and streams, without int overflow.

Two pointers comparing the characters of racecar from both ends toward the middle in a Java palindrome check

A palindrome is a string or a number that reads the same forward and backward, such as level, racecar or 1221, and a palindrome program in Java checks it by comparing characters from both ends toward the middle. For numbers, we reverse the digits with % 10 and / 10 and compare the result with the original.

We write palindrome checks in interviews and in text-processing code, and the same two-pointer technique appears in bioinformatics, where some DNA sequences mirror themselves.

The following example checks words, a phrase and a number with the methods from section 1, section 3 and section 5.

boolean level = isPalindrome("level");                                 // true
boolean java = isPalindrome("java");                                   // false
boolean phrase = isPalindromePhrase("A man, a plan, a canal: Panama"); // true
boolean number = isPalindromeNumber(1221);                             // true

The phrase needs its own method, because the spaces, commas and capital letters would break a plain character comparison. We start with the string checks, move on to recursion, streams and numbers, and finish with a real-world use and a comparison of all the methods.

1. Palindrome Program in Java with Two Pointers

The two-pointer check compares the first character with the last, the second with the second-to-last, and so on. It stops at the first mismatch, and if the two indexes meet in the middle without a mismatch, the string is a palindrome.

Two pointers comparing the characters of racecar from both ends toward the middle in a Java palindrome check
Three comparisons decide racecar, because the middle character e has no partner
static boolean isPalindrome(String s) {
    if (s == null) {
        return false;
    }
    for (int left = 0, right = s.length() - 1; left < right; left++, right--) {
        if (s.charAt(left) != s.charAt(right)) {
            return false;               // first mismatch decides
        }
    }
    return true;
}
boolean racecar = isPalindrome("racecar");   // true
boolean noon = isPalindrome("noon");         // true
boolean single = isPalindrome("x");          // true
boolean empty = isPalindrome("");            // true
boolean nothing = isPalindrome(null);        // false

The two-pointer check needs at most n / 2 comparisons and no extra memory, which makes it the best default for strings. An empty string and a single character are palindromes by definition, whereas null is not a string at all, so the method returns false instead of throwing an exception.

2. Palindrome Check by Reversing the String

The shortest version reverses the string with StringBuilder, as described in our reverse a string article, and compares the copy with the original. The call equalsIgnoreCase() makes the check ignore upper and lower case.

String word = "Madam";
boolean exact = word.equals(new StringBuilder(word).reverse().toString());              // false
boolean ignoreCase = word.equalsIgnoreCase(new StringBuilder(word).reverse().toString());   // true

The reverse-and-compare version always builds a full copy, even when the first and the last character already differ. That is fine for short strings, but the two-pointer version from section 1 does less work.

A common beginner version builds the reverse with reverse = reverse + s.charAt(i) in a loop. Each + copies the whole string built so far, so that loop costs O(n2) and is the slowest way to check a palindrome.

3. Ignoring Case, Spaces and Punctuation

Phrases such as “Was it a car or a cat I saw?” are palindromes only when we skip spaces and punctuation and compare letters without case. The two-pointer loop moves each index past characters that are not letters or digits, using Character.isLetterOrDigit(), and compares the rest in lower case.

static boolean isPalindromePhrase(String s) {
    if (s == null) {
        return false;
    }
    int left = 0;
    int right = s.length() - 1;
    while (left < right) {
        char l = s.charAt(left);
        char r = s.charAt(right);
        if (!Character.isLetterOrDigit(l)) {
            left++;
        } else if (!Character.isLetterOrDigit(r)) {
            right--;
        } else if (Character.toLowerCase(l) != Character.toLowerCase(r)) {
            return false;
        } else {
            left++;
            right--;
        }
    }
    return true;
}
boolean car = isPalindromePhrase("Was it a car or a cat I saw?");   // true
boolean nixon = isPalindromePhrase("No 'x' in Nixon");               // true
boolean almost = isPalindromePhrase("Was it a car or a dog I saw?"); // false

A shorter alternative cleans the string first with a regex and runs the plain check. It reads well, but it creates a new string, and the pattern [^A-Za-z0-9] also removes letters such as é or ü, which isLetterOrDigit() keeps.

String cleaned = "Step on no pets!".replaceAll("[^A-Za-z0-9]", "").toLowerCase();   // "steponnopets"
boolean pets = isPalindrome(cleaned);                                              // true

4. Recursive and Stream Versions

Interviewers sometimes ask for a recursive palindrome check. The recursive method compares the outer pair and calls itself for the inner part, and the base case is reached when the indexes meet. We pass indexes instead of calling substring(), so no characters are copied.

static boolean isPalindromeRecursive(String s, int left, int right) {
    if (left >= right) {
        return true;                    // base case
    }
    if (s.charAt(left) != s.charAt(right)) {
        return false;
    }
    return isPalindromeRecursive(s, left + 1, right - 1);
}
String kayak = "kayak";
boolean recKayak = isPalindromeRecursive(kayak, 0, kayak.length() - 1);   // true
String howto = "howtodoinjava";
boolean recHowto = isPalindromeRecursive(howto, 0, howto.length() - 1);   // false

Each call adds a stack frame, so a very long string can cause a StackOverflowError, as our recursion tutorial explains. With streams, IntStream.range() runs over the first half of the indexes, and allMatch() stops at the first mismatch, like the loop.

String radar = "radar";
boolean streamRadar = IntStream.range(0, radar.length() / 2).allMatch(i -> radar.charAt(i) == radar.charAt(radar.length() - 1 - i));   // true

5. Palindrome Number Program in Java

A number is a palindrome when its digits read the same in both directions, such as 121 or 1221. We take the last digit with n % 10, append it to a reversed number with reversed * 10 + digit, and remove it with n / 10. Negative numbers are not palindromes, because -121 read backward is 121-.

A full reversal can overflow an int. For example, 1,999,999,999 is a valid int, but its reverse 9,999,999,991 is not. The safe version reverses only the second half of the digits and compares it with the first half, so the reversed value never gets larger than the original.

static boolean isPalindromeNumber(int n) {
    if (n < 0 || (n % 10 == 0 && n != 0)) {
        return false;                   // negatives and numbers ending in 0
    }
    int reversedHalf = 0;
    while (n > reversedHalf) {
        reversedHalf = reversedHalf * 10 + n % 10;
        n /= 10;
    }
    return n == reversedHalf || n == reversedHalf / 10;   // even or odd digit count
}
boolean even = isPalindromeNumber(1221);        // true
boolean oddDigits = isPalindromeNumber(12321);  // true
boolean negative = isPalindromeNumber(-121);    // false
boolean tens = isPalindromeNumber(10);          // false
boolean zero = isPalindromeNumber(0);           // true
boolean maxInt = isPalindromeNumber(Integer.MAX_VALUE);   // false

For 12321, the loop stops with n = 12 and reversedHalf = 123, so the middle digit 3 is dropped with reversedHalf / 10. A number that ends in 0 cannot be a palindrome unless it is 0, because no number starts with 0.

Some palindrome programs try to ignore underscores in large numbers. Underscores such as 1_00_00_001 exist only in Java source code since Java 7, and the compiler removes them, so the int value has no underscores to ignore.

int withUnderscores = 1_00_00_001;                          // 10000001
boolean underscoreCheck = isPalindromeNumber(withUnderscores);   // true
boolean viaString = isPalindrome(String.valueOf(1_00_00_001));   // true

6. Palindromic Sites in DNA Sequences

In molecular biology, many restriction enzymes cut DNA at sites that read the same on both strands. The enzyme EcoRI recognizes GAATTC, and the complementary strand, read in its own direction, is also GAATTC. Software that scans a genome for such cutting sites runs the two-pointer check with one change, as it compares each base with the complement of its partner instead of the same base.

static boolean isReverseComplementPalindrome(String dna) {
    for (int left = 0, right = dna.length() - 1; left <= right; left++, right--) {
        char expected = switch (dna.charAt(left)) {
            case 'A' -> 'T';
            case 'T' -> 'A';
            case 'G' -> 'C';
            case 'C' -> 'G';
            default -> throw new IllegalArgumentException("Not a DNA base: " + dna.charAt(left));
        };
        if (dna.charAt(right) != expected) {
            return false;
        }
    }
    return true;
}
boolean ecoRI = isReverseComplementPalindrome("GAATTC");   // true
boolean plain = isPalindrome("GAATTC");                     // false
boolean other = isReverseComplementPalindrome("GATTTC");   // false

We can see that GAATTC is not a palindrome as plain text, yet it is the kind of palindrome that biologists care about. The loop runs to left <= right, because a middle base would have to be its own complement, which no DNA base is, so odd-length sequences are rejected.

7. Palindrome Methods Side by Side

All string checks run in O(n) time, but they differ in memory, in how early they stop and in what input they accept. The number check runs in O(d) time, where d is the number of digits.

MethodExtra memoryStops at first mismatchHandles phrasesNotes
Two pointersO(1)YesNoBest default for strings
Two pointers with skippingO(1)YesYesIgnores case, spaces and punctuation
StringBuilder.reverse() and equals()O(n)NoNoShortest code
Regex cleanup and checkO(n)NoYes, ASCII onlyDrops accented letters
Recursion with indexesO(n) stackYesNoInterview exercise
IntStream.allMatch()O(1)YesNoStream style
Half-digit reversalO(1)YesNot applicableNumbers, no overflow

All the string methods compare char values. For text with emoji or other characters outside the Basic Multilingual Plane, a check that compares s.codePoints().toArray() from both ends gives the correct answer.

8. Palindrome FAQs

Developers search for these questions and interviewers ask them about palindrome programs in Java.

8.1. How do we check a palindrome without reversing the string?

With the two-pointer loop from section 1. It compares characters from both ends, needs no copy of the string and returns at the first mismatch.

8.2. Is an empty string a palindrome?

Yes. An empty string reads the same in both directions, so all methods in this article return true for it, and the same holds for a single character.

8.3. Can a negative number be a palindrome?

No, under the usual definition. The minus sign is part of the number, and -121 read backward is 121-, which is not a number. If a task wants to ignore the sign, we pass Math.abs(n), except for Integer.MIN_VALUE, whose absolute value does not fit in an int.

8.4. Which palindrome check is the fastest?

The two-pointer check, because it reads at most half of the characters and allocates nothing. The StringBuilder version is fast enough for short strings, but it always copies the whole string.

8.5. How do we check a palindrome number by converting it to a String?

We call isPalindrome(String.valueOf(n)), as in the last example of section 5. It is short and correct for negative numbers too, because the minus sign never matches a digit, but it creates a string for each check.

9. Conclusion

A palindrome program in Java compares characters from both ends toward the middle and stops at the first mismatch, which needs no extra memory. For phrases, the same loop skips everything except letters and digits and compares in lower case.

For numbers, reversing only half of the digits avoids int overflow and handles negative numbers and trailing zeros. Reversing the whole string with StringBuilder is the shortest code, and the recursive and stream versions are useful for interviews, as long as we remember what each one costs.

10. References

Happy Learning !!

Source Code on Github

Leave a Comment

  1. class A
    {
    int v;
    A()
    {
    calc();
    }
    public void calc()
    {
    System.out.println(“A class Method “);
    }
    }
    class B extends A
    {
    B()
    {
    calc();
    }
    public void calc()
    {
    System.out.println(“B class Method “);
    }
    public static void main(String ar[])
    {
    A a1 = new B();
    }
    }

    output

    B class Method
    B class Method

    calc() method in A class is why not executed in A class Constuctor or why execute calc() method of B class
    sir plz solve my problem

    • Because you have override the method. Any method called is always first looked upon class which instance is being created. If not found there, ONLY then super class is looked upon. In both constructor calls, calc() method is found in B so JVM does not go beyond that i.e. A is not looked into.

      • We can easily do this in java using StringBuilder /StringBuffer also.

        StringBuilder str = new StringBuilder(“malayalam”);
        System.out.println(“reverse = ” + str.reverse());

        then compare original string and reversed one

Comments are closed.

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.