Problem
Given a signed 32-bit integer x, return x with its decimal digits reversed. The sign is preserved: reversing a negative number stays negative.
The environment can only store a signed 32-bit integer, meaning values in the range [-2^31, 2^31 - 1] = [-2147483648, 2147483647]. If the reversed value falls outside that range, return 0. You must detect the overflow without relying on a wider integer type to hold the intermediate result.
Examples
x = 123 → 321
Digits 1 2 3 reversed are 3 2 1.
x = -123 → -321
Reverse the magnitude 123 → 321, reattach the sign.
x = 120 → 21
Reversed digits are 0 2 1; leading zeros drop, leaving 21.
x = 1534236469 → 0
The reverse 9646324351 exceeds 2147483647, so it overflows and the answer is 0.
Constraints
-2^31 <= x <= 2^31 - 1 (x fits in a signed 32-bit int).
- The result must also fit in a signed 32-bit int, otherwise return
0.
- No 64-bit / big-integer type is available to hold the reversed value — the overflow check must happen before it would occur.
Think about it first
Hint 1
You can peel digits off the right end with `% 10` and drop them with `// 10`, building the reversed number as `rev = rev * 10 + digit`. The whole problem is one loop over the digits.
Hint 2
The only hard part is the overflow. The 32-bit ceiling is `INT_MAX = 2^31 - 1 = 0x7FFFFFFF`. Before you do `rev = rev * 10 + digit`, ask whether that operation *would* cross the ceiling.
Hint 3
`rev * 10 + digit` stays in range exactly when `rev <= (limit - digit) // 10`, where `limit` is the magnitude bound (`2^31 - 1` for a positive answer, `2^31` for a negative one). Check that guard each iteration and return `0` the moment it fails, so you never form the out-of-range value.
TL;DR
Pop digits with % 10 / // 10 and rebuild, guarding each step against the 32-bit boundary — O(log|x|) time, O(1) space.
Approach 1 — String reverse, check the bounds afterward (arithmetic brute force)
Turn the number into a string, reverse the characters, parse it back, and check the range at the end. This relies on Python’s arbitrary-precision integers to hold a value that might be too big for 32 bits, which is exactly the constraint the problem asks you to work without.
def reverse(x: int) -> int:
sign = -1 if x < 0 else 1
rev = sign * int(str(abs(x))[::-1])
if rev < -2**31 or rev > 2**31 - 1:
return 0
return rev
Complexity: O(d) time and O(d) space for d digits.
It works in Python only because int never overflows. In C/C++/Java the intermediate rev would silently wrap around before you could compare it, giving a wrong answer, so this sidesteps the stated problem rather than solving it.
Approach 2 — Digit arithmetic with a pre-overflow guard (the bit-level insight)
A signed 32-bit integer is one sign bit plus 31 magnitude bits, so the largest positive value is
INT_MAX = 2^31 - 1 = 0111 1111 1111 1111 1111 1111 1111 1111 (binary)
= 0x7FFFFFFF
= 2147483647 (decimal)
and the most negative is INT_MIN = -2^31 = 0x80000000 = -2147483648, whose magnitude is 2147483648 — one larger than INT_MAX. That asymmetry is why a positive result may reach at most ...647 but a negative result may reach a magnitude of ...648.
The operation that can overflow is rev = rev * 10 + digit. Instead of performing it and checking afterward, when the value has already wrapped, we check before multiplying whether the result will fit. Let limit be the magnitude bound for the answer’s sign. Then
rev * 10 + digit <= limit
<=> rev <= (limit - digit) // 10
If rev is already larger than (limit - digit) // 10, the next multiply-add would cross the boundary, so we stop and return 0. We never construct an out-of-range number, so no 64-bit type is needed. Working on abs(x) keeps % and // behaving like plain base-10 digit extraction (Python’s % on negatives rounds toward -inf, which would corrupt the digits).
def reverse(x: int) -> int:
sign = -1 if x < 0 else 1
limit = 2**31 if sign < 0 else 2**31 - 1 # magnitude ceiling for this sign
n = abs(x)
rev = 0
while n:
digit = n % 10
n //= 10
if rev > (limit - digit) // 10: # next step would overflow
return 0
rev = rev * 10 + digit
return sign * rev
Walkthrough on x = -123 (expect -321):
sign = -1, so limit = 2^31 = 2147483648; n = 123, rev = 0.
digit = 123 % 10 = 3, n = 12. Guard: 0 > (2147483648 - 3)//10? No. rev = 0*10 + 3 = 3.
digit = 12 % 10 = 2, n = 1. Guard: 3 > ...? No. rev = 3*10 + 2 = 32.
digit = 1 % 10 = 1, n = 0. Guard: 32 > ...? No. rev = 32*10 + 1 = 321.
- Loop ends; return
sign * rev = -1 * 321 = -321.
Walkthrough on x = 1534236469 (expect 0):
limit = 2147483647. Digits build rev up to 964632435 with one digit (1) left. Guard: 964632435 > (2147483647 - 1)//10 = 214748364? Yes, so return 0 before ever forming 9646324351.
Complexity: O(d) time (d ≈ 10 digits), O(1) space — no auxiliary storage, and crucially no value that ever leaves the 32-bit range.
Common pitfalls
- Checking overflow after the fact.
rev = rev*10+digit; if rev > INT_MAX: return 0 is wrong in any fixed-width language — rev has already wrapped. Guard before the multiply.
- Forgetting the asymmetric bound.
INT_MIN has magnitude 2^31, one more than INT_MAX = 2^31 - 1; a negative result reversed to ...648 is valid, its positive twin ...647+1 is not. Pick limit by sign.
- Python’s floor mod on negatives.
-123 % 10 == 7, not 3. Extract digits from abs(x) (or use truncating division) so the digits come out right.
- Trailing zeros.
120 → 21, not 021; building with rev*10+digit handles this for free since leading zeros contribute nothing.
Pattern takeaway
When a problem pins you to a fixed-width integer, translate the limit into its bit form (INT_MAX = 0x7FFFFFFF, INT_MIN = 0x80000000) and rearrange the risky operation into a predictive guard: test whether the next step would cross the boundary and refuse it, instead of performing it and checking after the fact. Check overflow one operation early, never one operation late.