Solving tips
- Peel digits with rev = rev*10 + (n % 10) and n //= 10; the whole solution is one loop over the digits.
- Check overflow BEFORE the multiply-add, never after: rev*10+digit fits iff rev <= (limit - digit)//10; bail out with 0 the moment it fails so you never form the out-of-range value.
- Mind the asymmetric 32-bit bound: positive answers cap at 2^31-1 but negative magnitudes reach 2^31, so pick limit by sign.
- Work on abs(x) so % and // behave as base-10 digit extraction (Python's % on negatives rounds toward -inf); O(log|x|) time, O(1) space.
Problem
Given a signed 32-bit integer x, return x with the order of its decimal digits reversed. The sign is preserved (reversing a negative number stays negative).
The catch: the environment can only store a signed 32-bit integer, i.e. 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 vanish, 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 bail out with `0` the moment it fails β you never form the out-of-range value at all.
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)
The obvious move: turn the number into a string, reverse the characters, parse it back, and check the range at the end. This leans entirely on Pythonβs arbitrary-precision integers to hold a value that might be too big for 32 bits β which is exactly the crutch the problem is testing whether you can live without.
class Solution:
def reverse(self, 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 got to compare it, giving a wrong answer β so this doesnβt actually solve the stated problem, it dodges it.
Approach 2 β Digit arithmetic with a pre-overflow guard (the bit-level insight)
The insight β think about where the 32-bit ceiling actually is. 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 push us over is rev = rev * 10 + digit. Rather than perform it and look afterward (too late β the value is already gone), we ask before multiplying whether the product 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 very 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).
class Solution:
def reverse(self, 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 β 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 inspecting the wreckage. The reusable move: overflow is checked one operation early, never one operation late.