Quantcast
Channel: Baeldung
Viewing all articles
Browse latest Browse all 3543

How to Check if a Number Is a Palindrome in Java

$
0
0

1. Overview

As we know, a number is a palindrome if it remains the same when its digits are reversed.

In this tutorial, we’ll explore different ways to check if a number is a palindrome, including iterative methods, recursive methods, and a few optimized ways to achieve our goal.

2. Problem Statement

Given a positive integer N, we want to find whether it’s a palindrome.

Input: N = 12321
Output: Yes
Explanation: 12321 is a palindrome number because after reversing its digits, it becomes 12321, the same as the original number.

Input: N = 123
Output: No
Explanation: 123 isn’t a palindrome number because after reversing its digits, the number becomes 321 which is different from the original number.

Now, let’s move into the approaches that help us find if a number is a palindrome.

3. Using Iterative Approach

The most straightforward way to check if a number is a palindrome is by reversing the digits and comparing the reversed number with the original one:

public static boolean isPalindromeIterative(int number) {
    int originalNumber = number;
    int reversedNumber = 0;

    while (number > 0) {
        int digit = number % 10;
	reversedNumber = reversedNumber * 10 + digit;
	number /= 10;
    }
    return originalNumber == reversedNumber;
}

So, we start by keeping a copy of the original number. This is important because we’ll need to compare it later. Next, we reverse the number by extracting its digits one by one. We do this by taking the number’s last digit and adding it to a new number we’re building, which starts at 0. Pulling each digit off the original number, we shrink it by dividing it by 10.

Let’s see the test case for the iterative approach:

@Test
void givenNumber_whenUsingIterativeApproach_thenCheckPalindrome() {     
    assertTrue(PalindromeNumber.isPalindromeIterative(12321));
    assertFalse(PalindromeNumber.isPalindromeIterative(123));
}

Once we’ve processed all the digits, we have a reversed version of the original number. The final step is to compare this reversed number with the original one we saved earlier. If they match, it means the number is a palindrome.

Let’s understand this logic:

  • Step 1: Set originalNumber = 12321 and reversedNumber = 0.
  • Step 2: Reverse the number
    • First digit: Extract 1, update the reversed number to 1, and reduce the number to 1232.
    • Second digit: Extract 2, update the reversedNumber to 12, and reduce the number to 123.
    • Third digit: Extract 3, update the reversedNumber to 123, and reduce the number to 12.
    • Fourth digit: Extract 2, update reversedNumber to 1232, and reduce the number to 1.
    • Fifth digit: Extract 1, update the reversedNumber to 12321, and reduce the number to 0.
  • Step 3: Since, reversedNumber (12321) matches the originalNumber (12321), so the number is a palindrome.

The loop runs once for each digit in the number. If the number has n digits, the time complexity is O(n). Each operation inside the loop (modulus, division, and multiplication) takes constant time O(1). So, the overall time complexity is O(n). And, we have used a constant amount of extra space for variables like originalNumber, reversedNumber, and digit, so the space complexity is O(1).

4. Using String Conversion

Another approach is to convert the number to a string, reverse it, and compare it with the original string:

public static boolean isPalindromeString(int number) {
    String original = String.valueOf(number);
    String reversed = new StringBuilder(original).reverse().toString();
    return original.equals(reversed);
}

In this approach, we first convert the number into a string. Then, we use a handy tool called StringBuilder to reverse that string. Once we have the reversed version, we compare it to the original string. If they match, the number is a palindrome.

Let’s see the test case for the string approach:

@Test
void givenNumber_whenUsingStringApproach_thenCheckPalindrome() {
    assertTrue(PalindromeNumber.isPalindromeString(12321));
    assertFalse(PalindromeNumber.isPalindromeString(123));
}

Let’s have a dry run of this code:

  • Step 1: Convert the number to String: original = “12321”.
  • Step 2: Reverse the string using the built-in method: reversed = “12321”.
  • Final step: Compare using original.equals(reversed). Since it returns true, it indicates that the number is a palindrome.

The loop in this approach iterates once for each digit in the number, leading to a time complexity of O(n), where n is the number of digits. Each operation within the loop, such as modulus, division, and multiplication, is performed in constant time, O(1). As for space complexity, only a constant amount of extra space is required for variables like originalNumber, reversedNumber, and digit, resulting in a space complexity of O(1).

5. Using Recursive Approach

We can also check for a palindrome using recursion, though it’s more complex and not as commonly used:

public static boolean isPalindromeRecursive(int number) {
    return isPalindromeHelper(number, 0) == number;
}

private static int isPalindromeHelper(int number, int reversedNumber) {
    if (number == 0) {
        return reversedNumber;
    }
    reversedNumber = reversedNumber * 10 + number % 10;
    return isPalindromeHelper(number / 10, reversedNumber);
}

In the recursive approach, we keep a copy of the original number. This is important because we’ll need to compare it later. Next, we reverse the number by extracting its digits one by one. We do this by taking the number’s last digit and adding it to a new number we’re building, which starts at zero. Pulling each digit off the original number, we shrink it by dividing it by 10.

Below is the test case for the recursive approach:

@Test
void givenNumber_whenUsingRecursiveApproach_thenCheckPalindrome() {
    assertTrue(PalindromeNumber.isPalindromeRecursive(12321));
    assertFalse(PalindromeNumber.isPalindromeRecursive(123));
}

Once we’ve processed all the digits, we have a reversed version of the original number. The final step is to compare this reversed number with the original one we saved earlier. If they match, it means the number is a palindrome.

Let’s dry-run this code to check if 12321 is a palindrome.

  • Step 1: Call isPalindromeHelper(12321, 0).
  • Step 2: Build reversed number recursively
    • First call: Reverse the last digit 1, update reversedNumber to 1, and call isPalindromeHelper(1232, 1).
    • Second call: Reverse 2, update reversedNumber to 12, and call isPalindromeHelper(123, 12)
    • Third call: Reverse 3, update reversedNumber to 123, and call isPalindromeHelper(12, 123).
    • Fourth call: Reverse 2, update reversedNumber to 1232, and call isPalindromeHelper(1, 1232).
    • Fifth call: Reverse 1, update reversedNumber to 12321, and call isPalindromeHelper(0, 12321).
  • Base case: Return reversedNumber (12321) and compare it with the originalNumber (12321). Since they match, it confirms that the number is a palindrome.

The recursive function is called once for each digit in the number, so the time complexity is O(n). Each recursive call involves a constant-time operation O(1). The recursion depth is equal to the number of digits in the number, so the space complexity is O(n) due to the call stack.

6. Half-Reversal Approach

This approach is more space-efficient than the full reversal method because it only reverses half of the number. The idea is to reverse the digits of the second half of the number and compare it with the first half.

Let’s understand this approach step by step along with its implementation and an example:

public static boolean isPalindromeHalfReversal(int number) {
    if (number < 0 || (number % 10 == 0 && number != 0)) {
        return false;
    }
    int reversedNumber = 0;
    while (number > reversedNumber) {
        reversedNumber = reversedNumber * 10 + number % 10;
        number /= 10;
    }
    return number == reversedNumber || number == reversedNumber / 10;
}

Here is the test case for the half-reversal approach:

@Test
void givenNumber_whenUsingHalfReversalApproach_thenCheckPalindrome() {
    assertTrue(PalindromeNumber.isPalindromeHalfReversal(12321));
    assertFalse(PalindromeNumber.isPalindromeHalfReversal(123));
}

Let’s dry-run this code to check if 12321 is a palindrome:

  • Initially, number = 12321 and reversedNumber = 0.
  • First iteration: number = 1232, reversedNumber = 1.
  • Second iteration: number = 123, reversedNumber = 12.
  • Third iteration: number = 12, reversedNumber = 123.
  • The loop stops because the number (12) is no longer greater than reversedNumber (123).
  • Since number == reversedNumber / 10, the function returns true.

Since we only process half of the digits, the time complexity is O(n), where n is the number of digits and we only use a few integer variables, so the space complexity is O(1).

7. Digit-by-Digit Comparison

This approach avoids reversing the number altogether by comparing digits from the start and end of the number moving toward the center.

Let’s understand this approach step by step along with its implementation and an example:

public static boolean isPalindromeDigitByDigit(int number) {
    if (number < 0) {
        return false;
    }
    int divisor = 1;
    while (number / divisor >= 10) {
        divisor *= 10;
    }
    while (number != 0) {
        int leading = number / divisor;
        int trailing = number % 10;
        if (leading != trailing) {
            return false;
        }
        number = (number % divisor) / 10;
        divisor /= 100;
    }
    return true;
}

Here’s the test case for this approach:

@Test
void givenNumber_whenUsingDigitByDigitApproach_thenCheckPalindrome() {
    assertTrue(PalindromeNumber.isPalindromeDigitByDigit(12321));
    assertFalse(PalindromeNumber.isPalindromeDigitByDigit(123));
}

Let’s run this code for 12321:

  • For 12321, initially, divisor = 10000, which is 10^(number of digits – 1).
  • Compare the first digit (1) with the last digit (1).
  • Remove both digits, adjust the divisor, and continue comparing.
  • If all digit pairs match, return true.

Since we compare digits from both ends moving towards the center, the time complexity is O(n), where n is the number of digits and we only use a few integer variables, so space complexity remains O(1).

8. Conclusion

In this article, we came across several approaches to check whether a number is palindrome. Choosing the right approach depends on our specific needs. If we’re looking for simplicity and can afford a bit more memory usage, the string conversion method might be our go-to. The half-reversal or digit-by-digit comparison methods offer excellent performance with minimal space overhead for a more efficient solution, especially with large numbers.

Each method has its charm, and understanding these different strategies can help us choose the most appropriate one for our situation, whether we prioritize readability, memory usage, or computational efficiency.

As always, the source code of all these examples is available over on GitHub.


Viewing all articles
Browse latest Browse all 3543

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>