Tracewise
← all guides
Easy Meet in the middle (digits) Jun 2, 2026

Palindrome Number

Decide whether an integer reads the same both ways — without converting it to a string, using the reverse-half technique.

#math#digit-manipulation#two-pointers#overflow

▣ tips & tricks — read first

what this problem is really testing

digit manipulationmath vs. stringsedge-case disciplineoverflow awarenessdo half the worksymmetry / mirroring

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.

inputoutputwhy
121true121 reversed is 121
-121falsereversed is "121-"; the sign breaks the mirror
10falsereversed 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.

1 x 2 2 1 rev
1221 folds in the middle → x = 12, rev = 12 (reversed). 12 = 12 ✓

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.

try:
left half · x 0
vs
reversed right · rev 0
while (x > rev): rev = rev*10 + x%10; x = x//10
press step ▸ to begin.

The two early rejections

Two kinds of numbers can be dismissed before any looping — they protect the rest of the logic.

guardexamplewhy it fails
x < 0-121The minus sign has no mirror on the right.
x % 10 == 0 and x != 010, 120Last 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.

stepxrevx > rev ?
start12210yes ↓
11221122 > 1 → yes ↓
2121212 > 12 → STOP
Crossover trace · x = 1221 → stops cleanly at the midpoint.

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:

stepxrevx >= rev ?
start12210yes ↓
11221122 >= 1 → yes ↓
2121212 >= 12 → yes ↓ (✗ should stop)
31122over-run: halves corrupted
1221 is a palindrome, yet x >= rev returns false.

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 lengthrev swallows the middle digit:

1 x 2 3 middle 2 1 rev
x = 12321 → loop ends at x = 12, rev = 123. Drop the middle: rev // 10 = 12 == x ✓

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 inguardloop ends (x, rev)returnresult
121pass(1, 12)1 == 12//10true
1221pass(12, 12)12 == 12true
12321pass(12, 123)12 == 123//10true
-121caughtfalse
10caughtfalse
0pass(0, 0)0 == 0true
Dry run across every branch and edge case.

Complexity

metriccostreason
timeO(log₁₀ n)We process half the digits; digit count grows logarithmically with the value.
spaceO(1)Two integers, no string buffer.

Pitfalls & pattern recognition