LeetCode #9 — Easy

Palindrome
Number

A visual walkthrough of the half-reversal approach — check if a number reads the same backwards, without converting it to a string.

Solve on LeetCode
The Problem

Problem Statement

Given an integer x, return true if x is a palindrome, and false otherwise.

Example 1:

Input: x = 121
Output: true
Explanation: 121 reads as 121 from left to right and from right to left.

Example 2:

Input: x = -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.

Example 3:

Input: x = 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.

Constraints:

  • -231 <= x <= 231 - 1
Follow up: Could you solve it without converting the integer to a string?

Roadmap

  1. The Brute Force — String Conversion
  2. The Core Insight — Reverse Only Half
  3. Algorithm Walkthrough
  4. Edge Cases
  5. Full Annotated Code
  6. Interactive Demo
  7. Complexity Analysis
Step 01

The Brute Force — String Conversion

The simplest approach: convert the integer to a string and check if it reads the same forwards and backwards.

String Approach

1
2
1
compare with
1
2
1
"121" == "121" reversed ✔
// Brute force: convert to string
public boolean isPalindrome(int x) {
    String s = String.valueOf(x);
    return s.equals(new StringBuilder(s).reverse().toString());
}

This works, but the follow-up question asks: can you do it without converting to a string? That eliminates the extra memory from string allocation and avoids character-by-character comparison.

💡

Why avoid strings? String conversion allocates O(log n) extra memory and adds overhead. A pure numeric approach uses O(1) space and gives us an elegant mathematical solution.

Step 02

The Core Insight — Reverse Only Half

The key idea: you don't need to reverse the entire number. Just reverse the second half and compare it to the first half. When the reversed portion grows to equal or exceed the remaining portion, you've crossed the middle.

Half-Reversal Strategy

For the number 1221, pop digits from the right and push them onto a reversed number. Stop when reversed >= x.

X (FIRST HALF)
1
2
2
1
REVERSED
-
-
Pop 1 from x, push onto reversed
X = 122
1
2
2
|
REV = 1
1
Pop 2 from x, push onto reversed
X = 12
1
2
REV = 12
1
2
reversed (12) >= x (12) → STOP! x == reversed ✔

Why only half? Reversing the entire number risks integer overflow for values near Integer.MAX_VALUE. By only reversing half, the reversed portion is at most the square root of the original — safely within integer range.

Odd-Length Numbers

For 12321 (5 digits), the reversed half overshoots by one digit. We simply discard the middle digit by comparing x == reversed / 10.

X = 12
1
2
REV = 123
1
2
3
x (12) == reversed / 10 (123 / 10 = 12) ✔
Step 03

Algorithm Walkthrough

Let's trace through the algorithm step by step with x = 123321.

Tracing x = 123321

Initial Check
x = 123321. Not negative, doesn't end in 0. Proceed to the loop.
x = 123321
reversed = 0
Iteration 1
Pop last digit: 123321 % 10 = 1. Push onto reversed: 0 * 10 + 1 = 1. Shrink x: 123321 / 10 = 12332.
x = 12332
reversed = 1
1
2
3
3
2
1
Iteration 2
Pop last digit: 12332 % 10 = 2. Push onto reversed: 1 * 10 + 2 = 12. Shrink x: 12332 / 10 = 1233.
x = 1233
reversed = 12
1
2
3
3
1
2
Iteration 3
Pop last digit: 1233 % 10 = 3. Push onto reversed: 12 * 10 + 3 = 123. Shrink x: 1233 / 10 = 123.
x = 123
reversed = 123
1
2
3
1
2
3
reversed (123) >= x (123) → STOP! x == reversed ✔ Palindrome!
🎯

The loop condition x > reversed is what makes this work. Each iteration, x shrinks (loses its last digit) and reversed grows (gains that digit). The moment reversed catches up, we've processed exactly half the digits.

Step 04

Edge Cases

Before entering the loop, we handle special cases with a single guard clause:

Negative Numbers
-121 → false
The minus sign means it can never read the same backwards. Caught by x < 0.
Trailing Zeros
10 → false
10 reversed is 01, which isn't a valid number. Any number ending in 0 (except 0 itself) fails. Caught by x % 10 == 0.
Single Digit
7 → true
Any single digit 0-9 is trivially a palindrome. The loop never executes (0 >= 7 is false), so we return x == reversed/10 which is 7 == 0... actually the loop runs once giving reversed=7, x=0. Then x == reversed/10 works.
Zero
0 → true
Zero is a palindrome. The guard x % 10 == 0 && x != 0 explicitly allows it through. The loop doesn't execute and reversed == x == 0.

The Guard Clause

// Two cases that are immediately NOT palindromes:
//   1. Negative numbers (the '-' sign breaks symmetry)
//   2. Numbers ending in 0 (except 0 itself, since no leading zeros)
if (x < 0 || (x % 10 == 0 && x != 0)) return false;
Step 05

Full Annotated Code

class Solution {
    public boolean isPalindrome(int x) {

        // Negative numbers are never palindromes
        // Numbers ending in 0 can't be palindromes (no leading zeros)
        // Exception: 0 itself IS a palindrome
        if (x < 0 || (x % 10 == 0 && x != 0)) return false;

        int reversed = 0;

        // Pop digits from x, push onto reversed
        // Stop when reversed has "caught up" to x (processed half the digits)
        while (x > reversed) {
            reversed = reversed * 10 + x % 10;   // push last digit of x
            x /= 10;                              // pop last digit from x
        }

        // Even length: x == reversed          (e.g. 1221 → x=12, rev=12)
        // Odd length:  x == reversed / 10     (e.g. 12321 → x=12, rev=123)
        // The middle digit doesn't affect palindrome check
        return x == reversed || x == reversed / 10;
    }
}
📝

Only three operations inside the loop: modulo to extract, multiply-and-add to build, integer divide to shrink. No strings, no arrays, no extra memory. Pure arithmetic elegance.

Step 06

Interactive Demo

Enter any integer and step through the half-reversal algorithm. Watch x shrink from the right while reversed grows.

⚙ Half-Reversal Visualizer


Step 07

Complexity Analysis

Time
O(log₁₀ n)
Space
O(1)

We process roughly half the digits of the number. Since a number n has log₁₀(n) digits, we do about log₁₀(n) / 2 iterations -- which is O(log₁₀ n). Each iteration performs one modulo, one multiplication, and one integer division, all O(1). Only a single integer variable (reversed) is used regardless of input size.

Approach Breakdown

STRING CONVERT
O(log n) time
O(log n) space

Converting the integer to a string produces log10(n) characters, then reversing and comparing scans them all. The string itself and its reversed copy each require O(log n) auxiliary memory.

FULL REVERSAL
O(log n) time
O(1) space

Extracts every digit via repeated modulo and integer division (log10(n) iterations), building the fully reversed number in a single integer variable. No string allocation needed, but risks overflow for values near Integer.MAX_VALUE.

HALF REVERSAL
O(log n) time
O(1) space

Processes only half the digits (log10(n) / 2 iterations) by popping digits from x and pushing onto reversed until they meet in the middle. The reversed half never exceeds the square root of the original, eliminating any overflow risk with just one integer variable.

🎯

Reversing only half avoids overflow entirely. A full reversal of a number near Integer.MAX_VALUE would overflow the reversed result. By stopping at the midpoint, the reversed half is at most the square root of the original -- safely within integer range, with no overflow check needed.

Coach Notes

Common Mistakes

Review these before coding to avoid predictable interview regressions.

Overflow in intermediate arithmetic

Wrong move: Temporary multiplications exceed integer bounds.

Usually fails on: Large inputs wrap around unexpectedly.

Fix: Use wider types, modular arithmetic, or rearranged operations.