9. Palindrome Number

Decide whether an integer reads the same forwards and backwards without converting it to a string. Reverse only the second half of the digits and compare it to the first half — half the work, and no overflow to worry about.

EasyMathTypeScript

PROBLEM What we're solving

Return true if integer x is a palindrome — it reads the same left-to-right and right-to-left. Examples: x = 121true; x = -121false (the leading minus has no trailing match); x = 10false (reversed it would be 01). The constraint: solve it without turning the number into a string.

KEY IDEA Reverse only the second half, then meet in the middle

Insight → you don't need the whole reversed number. Peel digits off the end of x into a growing reverted, while x shrinks from the front. The moment x ≤ reverted you have crossed the midpoint: reverted holds the reversed second half and x holds the remaining first half. A palindrome iff those two halves match.

RECIPE Reject cheaply, peel to the midpoint, compare

  • 0 · Cheap rejects. If x < 0it can't be a palindrome (the minus sign). If x % 10 === 0 and x !== 0, it ends in 0but doesn't start with one → reject.
  • 1 · Peel the second half. While x > reverted, push the last digit of x onto reverted = reverted * 10 + x % 10, then drop it with x = Math.trunc(x / 10). Stopping at x ≤ revertedmeans we only ever process half the digits — that's why there is no overflow concern.
  • 2 · Even length. If the number had an even count of digits, both halves are equal in size → palindrome iff x === reverted.
  • 3 · Odd length. The middle digit landed in reverted; discard it with Math.trunc(reverted / 10) and compare → palindrome iff x === Math.trunc(reverted / 10).
Classic confusion → people forget the trailing-zero reject and let 10 slip through, or they reverse the whole number and risk overflow. Reversing only half sidesteps overflow entirely, but then you must remember to drop the middle digit for odd-length inputs with reverted / 10.

COST Complexity & alternatives

Stringify & two-pointer
O(d)
Convert to a string and compare ends inward. Simple, but allocates a string — and the prompt asks you to avoid it.
Reverse half the digits
O(d)
O(d) time (d = digits ≤ 10), O(1) space. Only half the digits are processed; no overflow possible.

Both are O(d) in time where d is the digit count (≤ 10 for a 32-bit int), so effectively constant. The half-reversal wins on space (O(1)) and respects the no-string constraint, and because it never builds the full reversed value it can't overflow.

Pattern transfer → the “pop a digit with % 10, push with * 10 + d” idiom is exactly Reverse Integer (LC 7). Stopping at a midpoint mirrors the two-pointer meet-in-the-middle used for string/array palindromes, and the digit-by-digit processing reappears in Add Strings and Plus One.

RUN IT Reverse only the second half, then compare to the first

step 0 / 4
STARTInput: 121. We will reverse only the second half of the digits and compare it to the first half — no string conversion, no overflow risk.
1function isPalindrome(x: number): boolean {
2 // Negatives and any number ending in 0 (except 0 itself) are never palindromes.
3 if (x < 0 || (x % 10 === 0 && x !== 0)) return false;
4
5 let reverted = 0;
6 while (x > reverted) {
7 reverted = reverted * 10 + (x % 10); // push last digit of x onto reverted
8 x = Math.trunc(x / 10); // drop that digit from x
9 }
10
11 // Even length: x === reverted. Odd length: drop the middle digit (reverted / 10).
12 return x === reverted || x === Math.trunc(reverted / 10);
13}
State
121
x (remaining)
0
reverted
x — remaining first halfreverted — second halfhalves match → truemismatch / reject → false
slowfast

TYPESCRIPT The solution, annotated

palindromeNumber.ts
function isPalindrome(x: number): boolean {
  // Negatives and any number ending in 0 (except 0 itself) are never palindromes.
  if (x < 0 || (x % 10 === 0 && x !== 0)) return false;

  let reverted = 0;
  while (x > reverted) {
    reverted = reverted * 10 + (x % 10);  // push last digit of x onto reverted
    x = Math.trunc(x / 10);               // drop that digit from x
  }

  // Even length: x === reverted. Odd length: drop the middle digit (reverted / 10).
  return x === reverted || x === Math.trunc(reverted / 10);
}

Reading it block by block

Lines 1–2 — cheap rejects. A negative number has a leading -with no trailing counterpart, so it's never a palindrome. A number ending in 0 (other than 0 itself) would need to start with 0when reversed, which integers don't — reject both up front.
Lines 4–5 — set up the loop. reverted starts at 0. The condition x > reverted keeps peeling digits off the back of x until reverted has caught up to (or passed) x — the midpoint of the number.
Lines 6–7 — move one digit. reverted = reverted * 10 + (x % 10) pushes x's last digit onto reverted, then x = Math.trunc(x / 10) drops it. Math.trunc (not Math.floor) truncates toward zero, though after the early reject x is always non-negative here.
Line 11 — the two comparisons. For an even digit count the halves are equal size, so x === reverted. For an odd count the middle digit ended up inside reverted; Math.trunc(reverted / 10) chops it off so we can compare the remaining halves. Either match means palindrome.
Complexity → O(d) time where d = number of digits (≤ 10 for a 32-bit int) — and we touch only about half of them. O(1) space; no strings, arrays, or full reversal, so overflow never arises.

INTERVIEWFollow-ups they'll ask

  • “Could you do it as a string?” Yes — s === [...s].reverse().join('')or a two-pointer scan from both ends. It's O(d) space and the problem explicitly asks you to avoid it.
  • “Why reverse only half?” Reversing the whole number could overflow 32 bits; reversing half never builds a value larger than the original, so overflow is impossible and you do half the work.
  • “How do you handle odd vs even length?” The loop stops at the midpoint either way. Even: x === reverted. Odd: the middle digit sits in reverted, so compare against Math.trunc(reverted / 10).
  • “What about edge cases?” 0true; -121false; 10false via the trailing-zero check.

OPTIMAL Math

palindromeNumber.ts
function isPalindrome(x: number): boolean {
  // Negatives and any number ending in 0 (except 0 itself) are never palindromes.
  if (x < 0 || (x % 10 === 0 && x !== 0)) return false;

  let reverted = 0;
  while (x > reverted) {
    reverted = reverted * 10 + (x % 10);  // push last digit of x onto reverted
    x = Math.trunc(x / 10);               // drop that digit from x
  }

  // Even length: x === reverted. Odd length: drop the middle digit (reverted / 10).
  return x === reverted || x === Math.trunc(reverted / 10);
}
Complexity → O(d) time where d = number of digits (≤ 10 for a 32-bit int) — and we touch only about half of them. O(1) space; no strings, arrays, or full reversal, so overflow never arises.

ALT 1 Stringify and two-pointer compare

O(d) time · O(d) space

The straightforward approach the prompt asks you to avoid: render the number as a string and compare characters inward from both ends.

approach-2.ts
function isPalindrome(x: number): boolean {
  if (x < 0) return false;
  const s = String(x);
  let i = 0;
  let j = s.length - 1;
  while (i < j) {
    if (s[i] !== s[j]) return false;
    i++;
    j--;
  }
  return true;
}
Note → Correct and easy to read, but it allocates an O(d) string and ignores the “no string conversion” constraint. The half-reversal does it in O(1) space with no overflow risk.

MNEMONIC The one-liner

"Reject negatives and trailing zeros, then peel digits into reverted until x dips below it — match the halves (drop the middle for odd)."

TRIGGERS When you see ___ → reach for ___

palindrome integer without a stringreverse only the second half
when to stop peeling digitsloop while x > reverted (midpoint)
odd number of digitscompare x to Math.trunc(reverted / 10)
instant false casesx < 0, or x % 10 === 0 && x !== 0

SKELETON The reusable shape

skeleton.ts
function isPalindrome(x: number): boolean {
  if (x < 0 || (x % 10 === 0 && x !== 0)) return false;
  let reverted = 0;
  while (x > reverted) {
    reverted = reverted * 10 + (x % 10);
    x = Math.trunc(x / 10);
  }
  return x === reverted || x === Math.trunc(reverted / 10);
}

FLASHCARDS Tap to flip

Which numbers are rejected before any work?
Negatives (x < 0) and any non-zero number ending in 0 (x % 10 === 0 && x !== 0).
tap to flip
1 / 7
Answer to reveal explanations. No penalty for retries.Score: 0 / 9
QUESTION 01
Why is x = -121 not a palindrome?
QUESTION 02
What is the loop-stopping condition for the half-reversal?
QUESTION 03
For an odd number of digits, what is the final comparison?
QUESTION 04
Why does x = 10 return false?
QUESTION 05
Why reverse only the second half of the digits rather than the whole number?
QUESTION 06
What is the space complexity of the half-reversal solution?
QUESTION 07
Trace x = 121. What are x and reverted when the loop stops?
QUESTION 08
#9 · Palindrome NumberDecide whether an integer reads the same forwards and backwards without converting it to a string by reversing only its second half and comparing it to the first. Negatives and trailing-zero numbers are never palindromes. O(log₁₀ x).Which algorithmic approach does this primarily use?
QUESTION 09
#9 · Palindrome NumberDecide whether an integer reads the same forwards and backwards without converting it to a string by reversing only its second half and comparing it to the first. Negatives and trailing-zero numbers are never palindromes. O(log₁₀ x).Which implementation correctly solves it?