DSAPrep
EasyMath & Geometry

Palindrome Number

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

A palindrome reads the same forward and backward. The natural instinct is to stringify x and compare the string with its reverse β€” but the follow-up asks whether that can be done without converting the integer to a string, which is exactly what the optimal solution below does with arithmetic only.

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

  • -2^31 <= x <= 2^31 - 1
Follow-up: Could you solve it without converting the integer to a string?
View original on LeetCode β†—

The pattern here is reversing a number from the right with arithmetic β€” peeling off one digit at a time with x % 10, shifting it onto a growing reversed value, and shrinking x with x // 10. The trick that makes this efficient is to stop early: you only need to reverse half of x, not all of it, because a palindrome is symmetric. Stop the moment the reversed half catches up to the remaining half β€” that is the sign you have passed the middle β€” then compare the two halves. Two arithmetic facts make the whole thing possible: x % 10 always yields the units digit, and every digit you peel restores the number by dividing by ten, so the peeled digits come out in exact reverse order for free.

Brute Force: String Reversal

Time O(n)Space O(n)

Turn x into a string, reverse that string, and compare. This is the direct reading of the definition β€” β€œdoes x read the same forward and backward?” β€” and it is correct on every input. The string makes the minus sign a character, so a negative number like -121 becomes "121-" reversed and is naturally not equal; the trailing-zero trap also resolves itself because "10" reversed is "01".

class Solution:
def isPalindrome(self, x: int) -> bool:
s = str(x)
return s == s[::-1]

Why it is not ideal: building the string costs O(n) time, where n is the number of digits in x, and the reversed copy costs another O(n) space on top of the original β€” so the whole input is duplicated in memory. For a 32-bit integer those constants are tiny, but the larger cost is conceptual: the follow-up explicitly asks for a no-string solution, and converting to a string sidesteps the very arithmetic that makes this a β€œMath & Geometry” problem. It also cannot extend to very large integers without first paying the full stringification bill for a comparison that only ever needs the outer half.

Reverse Half of the Number

OptimalTime O(log n)Space O(1)

Reverse only the second half of x and compare it with the first half. Handle the easy failures up front: a negative number is never a palindrome, and a positive number ending in 0 has a first digit that could never match that trailing 0 (no leading zeros allowed) β€” so both are rejected immediately. Then peel digits from the right into a running rev and shrink x by dividing by ten, stopping the moment rev reaches x (the middle). Because x is halved each round, the loop runs about as many times as there are half the digits β€” roughly O(log n) rounds, not O(n). For even-digit palindromes the two halves match exactly; for odd-digit ones the extra middle digit stays in x, so the final check accepts either x == rev or x == rev // 10.

class Solution:
def isPalindrome(self, x: int) -> bool:
if x < 0 or (x % 10 == 0 and x != 0):
return False
rev = 0
while rev < x:
rev = rev * 10 + x % 10
x //= 10
return x == rev or x == rev // 10

Watch the half-reversal on x = 121 β€” the odd-length case where the middle digit stays behind in x and the halves align only after dropping that digit:

special cases pass
x
121
rev
0
the halves are compared only at the middle

each peel moves one digit from the right of x into the right of rev; the loop stops the moment rev catches up to x, so the halves are compared at the middle β€” never by scanning the whole number

1 / 6
currentcomparingdiscardedresult

Reverse the second half of x and compare it with the first half. Two special cases first: a negative number is never a palindrome, and a positive number ending in 0 is never one either. x = 121 is neither, so a palindrome is still possible. Now peel digits off the right end of x and build rev from them, stopping the instant rev catches up to x β€” that point is the middle where the two halves meet.

Then x = 10 β€” the trailing-zero edge case caught up front with no peeling at all:

trailing-zero rule
x
10
rev
0
the halves are compared only at the middle

each peel moves one digit from the right of x into the right of rev; the loop stops the moment rev catches up to x, so the halves are compared at the middle β€” never by scanning the whole number

1 / 2
currentcomparingdiscardedresult

Now x = 10. Before any peeling, the trailing-zero rule applies: x is positive and its last digit is 0, so x is rejected immediately. The reason: a palindrome whose first digit must mirror that trailing 0 would have to start with 0, and a number never has a leading zero. So the checks fail with no work done.

Why it is O(log n): the loop divides x by ten every iteration and stops once rev catches x, so it peels roughly half of the digits β€” about log10(x) / 2 rounds, written O(log n) where n is the value of x (each round is constant work). It contrasts sharply with the brute-force string version, which touches and duplicates all n digits. Space is O(1): only the two integer variables x and rev exist, with no array or string. Correctness rests on the two earlier-rejected edge cases being handled before the loop, plus the x == rev // 10 branch that reconciles the odd-length palindrome where the middle digit never leaves x. The guard also naturally accepts x = 0, since 0 is a palindrome and neither rejection condition applies.