Palindrome Number
Decide whether an integer reads the same both ways — without converting it to a string, using the reverse-half technique.
▣ tips & tricks — read first
what this problem is really testing
An interviewer asking this rarely cares about the answer for 121. They’re probing whether you reach for integer arithmetic instead of str(x), whether you spot the edge cases unprompted, and whether you notice you only need to reverse half the number.
mental model
A palindrome has mirror symmetry around its center. Instead of comparing the whole number to its full reverse, fold the back half onto the front half and check they match. The center is the pivot; everything outward must mirror.
pattern toolkit — when you see X, reach for Y
“Same forwards & backwards” / mirror
Two pointers from both ends inward, or reverse-half and compare.
Work on a number’s digits (no strings)
The peel loop: d = n % 10 grabs the last digit, n //= 10 drops it.
Build a number up from digits
Accumulate: acc = acc * 10 + d — append a digit on the right.
Reversing the whole thing may overflow
Process only half, or compare as you go — never hold the full reverse.
Even-vs-odd length changes the answer
Handle the lone middle element separately — usually just drop it.
Stop at the midpoint without counting
Let two converging values cross: while x > rev.
edge-case reflexes — ask before coding
- Can the input be negative? (Sign has no mirror → instant false.)
- Are there leading or trailing zeros? (A nonzero number can’t start with 0.)
- What about 0, a single digit, or empty? (Usually trivially true — don’t crash.)
- Can the math overflow the integer range?
- Did I cover both even and odd sizes?
The problem
Given an integer x, return true if x is a palindrome and false otherwise. A palindrome reads identically left-to-right and right-to-left.
| input | output | why |
|---|---|---|
| 121 | true | 121 reversed is 121 |
| -121 | false | reversed is "121-"; the sign breaks the mirror |
| 10 | false | reversed is "01"; the leading zero can’t exist |
Constraint: −2³¹ ≤ x ≤ 2³¹ − 1. Follow-up: solve it without converting the integer to a string.
Two approaches & how we chose
Approach A — reverse the whole number. Reverse every digit into a new integer and compare to the original. It works, but reversing the entire number can overflow the 32-bit range, and the follow-up nudges us toward something cleaner.
Approach B — reverse only the back half (what we use). Peel digits off the right of x and build them into a second number rev. Stop once rev has consumed half the digits, then compare the two halves. We never hold more than half the number, so overflow is impossible and we do half the work.
The core idea
Two operations are the entire engine — the universal toolkit for chewing through a number digit by digit:
x % 10 # last digit of x (1221 % 10 = 1)
x // 10 # x with last digit removed (1221 // 10 = 122)
Each iteration moves one digit from the right of x onto rev:
rev = rev * 10 + x % 10 # append x's last digit to rev
x = x // 10 # drop that digit from x
So x shrinks from the right while rev grows from the left. When they meet in the middle, the front half lives in x and the reversed back half lives in rev — and we just compare them.
Interactive walkthrough
Pick a number and press step to peel one digit at a time. Watch x shrink and rev grow until they cross.
The two early rejections
Two kinds of numbers can be dismissed before any looping — they protect the rest of the logic.
| guard | example | why it fails |
|---|---|---|
| x < 0 | -121 | The minus sign has no mirror on the right. |
| x % 10 == 0 and x != 0 | 10, 120 | Last digit is 0, but no number starts with 0. |
Note the and x != 0: zero itself is a palindrome, so we must let it through.
Why while x > rev
The loop must stop after processing exactly half the digits — but we never counted them. The condition x > rev is a free digit-counter, because a number with more digits is always larger than one with fewer (and we already ruled out leading-zero cases). So x > rev really means “x still holds more than half the digits — keep folding.” The instant rev catches up, we stop.
| step | x | rev | x > rev ? |
|---|---|---|---|
| start | 1221 | 0 | yes ↓ |
| 1 | 122 | 1 | 122 > 1 → yes ↓ |
| 2 | 12 | 12 | 12 > 12 → STOP |
Worked example: what x >= rev does to 1221
Don’t take it on faith — run the broken version. With >=, the loop takes one extra iteration at the midpoint, and that single step wrecks both halves:
| step | x | rev | x >= rev ? |
|---|---|---|---|
| start | 1221 | 0 | yes ↓ |
| 1 | 122 | 1 | 122 >= 1 → yes ↓ |
| 2 | 12 | 12 | 12 >= 12 → yes ↓ (✗ should stop) |
| 3 | 1 | 122 | over-run: halves corrupted |
Why x == rev or x == rev // 10
We don’t know in advance whether the number has an even or odd digit count, and the loop stops in a slightly different place for each. One or handles both.
Even length — for 1221 the loop ends at x = 12, rev = 12. Same length, so x == rev settles it.
Odd length — rev swallows the middle digit:
A single middle digit is automatically a palindrome — it mirrors itself — so we discard it with rev // 10. Because a number is either even- or odd-length (never both), exactly one side of the or applies and the other is harmlessly ignored.
Implementation
def isPalindrome(x: int) -> bool:
# Guard 1: negatives can't be palindromes (the sign has no mirror).
# Guard 2: a nonzero multiple of 10 ends in 0 but can't start with 0.
if x < 0 or (x % 10 == 0 and x != 0):
return False
rev = 0
# Fold digits off the right of x onto rev until rev catches up.
while x > rev:
rev = rev * 10 + x % 10 # append x's last digit to rev
x //= 10 # drop that digit from x
# Even length: halves equal. Odd length: drop rev's middle digit.
return x == rev or x == rev // 10
| x in | guard | loop ends (x, rev) | return | result |
|---|---|---|---|---|
| 121 | pass | (1, 12) | 1 == 12//10 | true |
| 1221 | pass | (12, 12) | 12 == 12 | true |
| 12321 | pass | (12, 123) | 12 == 123//10 | true |
| -121 | caught | — | — | false |
| 10 | caught | — | — | false |
| 0 | pass | (0, 0) | 0 == 0 | true |
Complexity
| metric | cost | reason |
|---|---|---|
| time | O(log₁₀ n) | We process half the digits; digit count grows logarithmically with the value. |
| space | O(1) | Two integers, no string buffer. |