Integer Overflow Handling & Digit Manipulation
Take a signed 32-bit integer x and flip its digits end to end. If that flipped value would spill outside the signed 32-bit window [-231, 231 - 1], return 0 instead.
Treat 64-bit integer storage (signed or unsigned) as unavailable to you.
123 reversed is 321.Digit Manipulation
integer x ➔ digit modulo extraction ➔ overflow clamp| 1 | def reverse_integer(x: int) -> int: |
| 2 | """Reverses digits of a 32-bit signed integer with overflow detection. |
| 3 | Time: O(log10 |x|) | Space: O(1) |
| 4 | """ |
| 5 | INT_MAX = 2**31 - 1 # 2147483647 |
| 6 | INT_MIN = -2**31 # -2147483648 |
| 7 | |
| 8 | # 1. Normalize the Sign: |
| 9 | # Python's % and // round toward minus infinity, so working on a |
| 10 | # negative x directly would misbehave; the sign is split off and reapplied at the end. |
| 11 | sign = -1 if x < 0 else 1 |
| 12 | x = abs(x) |
| 13 | res = 0 # digits of x, read from the right, rebuilt in reverse order |
| 14 | |
| 15 | # 2. Peel Off and Append One Digit at a Time: |
| 16 | # x % 10 reads the last digit and x //= 10 drops it; appending that |
| 17 | # digit to res with res * 10 + digit builds the reversed number one digit per step. |
| 18 | while x > 0: |
| 19 | digit = x % 10 |
| 20 | x //= 10 |
| 21 | |
| 22 | # 3. Detect Overflow Before It Happens: |
| 23 | # res * 10 + digit must stay within INT_MAX; checking res against |
| 24 | # INT_MAX // 10 first catches the overflow before the multiply can occur. |
| 25 | if res > INT_MAX // 10 or (res == INT_MAX // 10 and digit > 7): |
| 26 | return 0 |
| 27 | |
| 28 | res = res * 10 + digit |
| 29 | |
| 30 | # 4. Reapply the Sign and the Final Range Check: |
| 31 | # The sign set aside in step 1 is multiplied back in, then the result |
| 32 | # is re-checked against the full signed range in case that flipped it out of bounds. |
| 33 | res *= sign |
| 34 | return res if INT_MIN <= res <= INT_MAX else 0 |
res is the reverse of the digits already removed from x, and it is checked against INT_MAX // 10 before every append.Treat a number as a row of digits: x % 10 reads the last digit, x //= 10 drops it, and res = res * 10 + digit appends a digit on the right, so any number can be taken apart and rebuilt one digit at a time without turning it into a string. Each step moves exactly one digit, so reading from the right while appending builds the digits in reverse order, as reverse_integer does; the same two moves, in other orders, compare a number with its mirror, add numbers stored as digit arrays or parse text into a number. Work on abs(x) and put the sign back at the end, because in Python % and // round toward minus infinity for negatives (-7 % 10 == 3). The trap is overflow: test res > INT_MAX // 10 (or res == INT_MAX // 10 and digit > 7) before res * 10 + digit, because with fixed-width integers the multiply itself overflows: Java silently wraps the value around, and in C++ signed overflow is undefined behavior.
See it run
Digit Manipulation, step by step
x 1534236469res 0INT_MAX // 10 214748364
Each column is one digit position. The top row is the digits of x still to read, and a digit is cleared after it is read. The bottom row is the digits of res, in the order they were appended.
digitthe last digit of x, read by x % 10appendthe digit just added to the right end of restoo bigres when it is above INT_MAX // 10 and the next multiply would overflow
Start: x = 1534236469 and res = 0. The loop runs while x > 0.
Gotcha 1 of 3
- The trap
Gotcha 1: Checking the 32-bit limit after
res * 10 + digitMistakeres = res * 10 + digit if res > INT_MAX: return 0Fixif res > INT_MAX // 10 or (res == INT_MAX // 10 and digit > 7): return 0 res = res * 10 + digitWhat happens: In Java or C++,
resis a 32-bit integer.res * 10 + digitcan go pastINT_MAX, which is 2^31 - 1. Java then wraps the value around, and in C++ signed overflow is undefined behavior. A check after the multiply only sees the wrapped value. For x = 1534236469, the true reverse is 9646324351, and Java's wrapped value is 1056389759. That value is belowINT_MAX, so the late check lets it through. Python ints never overflow, so in Python both orders return 0. The check before the multiply is the one that works in every language.
- The number must be reversed in binary, always 32 bits wide, as in Reverse Bits (LC 190), not in base 10. See Bit Tricks
Deep Dive
Three moves: read, drop and append
A number can be taken apart and rebuilt without a string. Three moves are enough. x % 10 reads the last digit. x //= 10 drops the last digit. res = res * 10 + digit adds a digit at the right end of res.
Each loop round moves one digit from the right end of x to the right end of res. The first digit read is the last digit of x, and it becomes the first digit of res. So res holds the digits in reverse order.
Example: x = 123. Round 1 reads 3, so x = 12 and res = 3. Round 2 reads 2, so x = 1 and res = 32. Round 3 reads 1, so x = 0 and res = 321. The loop stops because x > 0 is false.
A trailing zero is handled without extra code. For x = 120, the first digit is 0, so res = 0 * 10 + 0 = 0. The next digits give res = 2 and then res = 21. The answer is 21.
Check the limit before the multiply
INT_MAX is 2147483647, and INT_MAX // 10 is 214748364. After the multiply, res * 10 + digit must not be above INT_MAX. So before the multiply, res must not be above 214748364. If res is exactly 214748364, the last digit must be at most 7.
Trace for x = 1534236469. The first nine digits give res = 964632435. This is above 214748364, so the tenth digit, 1, is never appended. The function returns 0. The true reverse is 9646324351, which does not fit in 32 bits.
The check must come first. Java and C++ use 32-bit integers. In Java, res * 10 + digit wraps around and gives 1056389759 for this input. That value is below INT_MAX, so a check after the multiply passes by mistake. In C++, signed overflow is undefined behavior. Python integers have no limit, so Python hides this problem, but the same order is correct in every language.
For a valid 32-bit input with 10 digits, the first digit is 1 or 2. That digit is the last one appended, so the test digit > 7 never fires for a valid input. It stays in the blueprint so that the rule is exact for the limit 2147483647.
Negative numbers in Python
In Python, % and // round toward minus infinity. So -7 % 10 is 3 and -7 // 10 is -1. On a negative x, the loop x //= 10 stops at -1 and never reaches 0, so the loop never ends.
The blueprint avoids this. It stores sign = -1 if x < 0 else 1 and works on x = abs(x). After the loop, res *= sign puts the sign back. For x = -123 the answer is -321.
Last, the blueprint checks INT_MIN <= res <= INT_MAX. The test before each multiply used only the positive limit, so this final check covers the negative side.
Do not reverse the digits through a string. str(-123)[::-1] is "321-", and int("321-") raises ValueError. The string version also still needs the 32-bit check.
The same moves in other orders
The three moves solve a family of problems. Only the order and the stopping rule change.
Palindrome Number (LC 9) reverses only the second half of the digits. The loop while x > rev: rev = rev * 10 + x % 10; x //= 10 stops at the middle. The number is a palindrome when x == rev or x == rev // 10. A negative number, or a number that ends in 0 but is not 0, is rejected first. Here rev never gets larger than x, so no overflow check is needed.
String to Integer (atoi) (LC 8) parses text with the same append, res = res * 10 + digit, and the same check before the multiply. It clamps the result to the limit instead of returning 0. Plus One (LC 66) and Multiply Strings (LC 43) walk over digit arrays and carry one digit to the next.
The loop runs once per digit, so the time is O(log10 |x|), which is at most 10 rounds for a 32-bit number. The extra space is O(1).
60-Second Pitch
"I take the number apart one digit at a time. x % 10 reads the last digit, x //= 10 drops it, and res = res * 10 + digit appends it. Reading from the right and appending on the right reverses the digits. In Python, % and // round toward minus infinity, so I store the sign and work on abs(x). The risk is overflow. In a language with 32-bit integers, the multiply can already wrap, so I test res > INT_MAX // 10 before I multiply, with the extra case res == INT_MAX // 10 and digit > 7. If the test is true, I return 0. The time is O(log10 |x|), at most 10 rounds for a 32-bit number, and the space is O(1)."
Common Questions
- Why do you check
res > INT_MAX // 10before the multiply? With 32-bit integers,
res * 10 + digitcan overflow during the multiply. Java wraps the value around, and C++ has undefined behavior. A check afterwards sees the damaged value. The check before the multiply decides in advance. Ifresis below 214748364, any digit is safe. Ifresis exactly 214748364, only the digits 0 to 7 are safe. Ifresis above 214748364, no digit is safe.- Why do you work on
abs(x)and restoresignat the end? In Python,
%and//round toward minus infinity, so-7 % 10is 3 and-7 // 10is -1. A loop on a negativexnever reaches 0. Working onabs(x)avoids that, andres *= signputs the sign back.- What does
x = 120return, and why? It returns 21. The first digit read is 0, so
resstays 0. The next digits makeres = 2and thenres = 21. The reverse as text is021, and as a number that is 21.- What are the time and space complexity?
The time is O(log10 |x|), because each round removes one digit. For a 32-bit number that is at most 10 rounds. The space is
O(1), because the code keeps onlyx,res,digitandsign.- How does the same idea check a palindrome number?
Palindrome Number (LC 9) reverses only the second half. The loop
while x > revmoves digits fromxtorev. Thenx == revhandles an even number of digits, andx == rev // 10handles an odd number. Negative numbers, and numbers that end in 0 but are not 0, are rejected first.
SWE Reasoning
Spot it
- The problem builds, reverses, compares or parses a number one digit at a time (Reverse Integer (LC 7), Palindrome Number (LC 9), String to Integer (atoi) (LC 8)).
- The result must be 0, or must be clamped, when it leaves the 32-bit range.
- Converting the number to a string would work but is not allowed, or needs extra care for the sign.
- The code runs in a language with fixed-width integers, where the multiply itself can overflow.
The invariant, step by step
signis stored andx = abs(x).resis 0.- Each round reads
digit = x % 10and drops it withx //= 10. The digit moves fromxtores. - Before the append, the code tests
res > INT_MAX // 10, andres == INT_MAX // 10 and digit > 7. If the test is true,res * 10 + digitwould be aboveINT_MAX, and the function returns 0. - If the test is false,
res = res * 10 + digitis safe.resis the reverse of the digits already removed fromx. - When
xis 0, all digits have moved, andresis the reverse of the original digits. res *= signrestores the sign. The final range check returns 0 if the signed value is outside the 32-bit range.
Traps
- Checking after the multiply. In Java,
res * 10 + digithas already wrapped. Forx = 1534236469, the wrapped value is 1056389759, which is belowINT_MAX, so the late check does not fire. - Using
%and//on a negativex. In Python,-7 // 10is -1, sox != 0never becomes false and the loop never ends. Useabs(x)and applysignat the end. - Reversing through a string.
int(str(-123)[::-1])raisesValueError, because the string is"321-". - Wrong limit. Testing
res > INT_MAXinstead ofres > INT_MAX // 10does not protect the multiply. Aresof 300000000 passes that test, and thenres * 10is aboveINT_MAX.
Practice
Integer Overflow Handling & Digit Manipulation
Take a signed 32-bit integer x and flip its digits end to end. If that flipped value would spill outside the signed 32-bit window [-231, 231 - 1], return 0 instead.
Treat 64-bit integer storage (signed or unsigned) as unavailable to you.
123 reversed is 321.Digit Manipulation
integer x ➔ digit modulo extraction ➔ overflow clamp| 1 | def reverse_integer(x: int) -> int: |
| 2 | """Reverses digits of a 32-bit signed integer with overflow detection. |
| 3 | Time: O(log10 |x|) | Space: O(1) |
| 4 | """ |
| 5 | INT_MAX = 2**31 - 1 # 2147483647 |
| 6 | INT_MIN = -2**31 # -2147483648 |
| 7 | |
| 8 | # 1. Normalize the Sign: |
| 9 | # Python's % and // round toward minus infinity, so working on a |
| 10 | # negative x directly would misbehave; the sign is split off and reapplied at the end. |
| 11 | sign = -1 if x < 0 else 1 |
| 12 | x = abs(x) |
| 13 | res = 0 # digits of x, read from the right, rebuilt in reverse order |
| 14 | |
| 15 | # 2. Peel Off and Append One Digit at a Time: |
| 16 | # x % 10 reads the last digit and x //= 10 drops it; appending that |
| 17 | # digit to res with res * 10 + digit builds the reversed number one digit per step. |
| 18 | while x > 0: |
| 19 | digit = x % 10 |
| 20 | x //= 10 |
| 21 | |
| 22 | # 3. Detect Overflow Before It Happens: |
| 23 | # res * 10 + digit must stay within INT_MAX; checking res against |
| 24 | # INT_MAX // 10 first catches the overflow before the multiply can occur. |
| 25 | if res > INT_MAX // 10 or (res == INT_MAX // 10 and digit > 7): |
| 26 | return 0 |
| 27 | |
| 28 | res = res * 10 + digit |
| 29 | |
| 30 | # 4. Reapply the Sign and the Final Range Check: |
| 31 | # The sign set aside in step 1 is multiplied back in, then the result |
| 32 | # is re-checked against the full signed range in case that flipped it out of bounds. |
| 33 | res *= sign |
| 34 | return res if INT_MIN <= res <= INT_MAX else 0 |
res is the reverse of the digits already removed from x, and it is checked against INT_MAX // 10 before every append.Treat a number as a row of digits: x % 10 reads the last digit, x //= 10 drops it, and res = res * 10 + digit appends a digit on the right, so any number can be taken apart and rebuilt one digit at a time without turning it into a string. Each step moves exactly one digit, so reading from the right while appending builds the digits in reverse order, as reverse_integer does; the same two moves, in other orders, compare a number with its mirror, add numbers stored as digit arrays or parse text into a number. Work on abs(x) and put the sign back at the end, because in Python % and // round toward minus infinity for negatives (-7 % 10 == 3). The trap is overflow: test res > INT_MAX // 10 (or res == INT_MAX // 10 and digit > 7) before res * 10 + digit, because with fixed-width integers the multiply itself overflows: Java silently wraps the value around, and in C++ signed overflow is undefined behavior.
See it run
Digit Manipulation, step by step
x 1534236469res 0INT_MAX // 10 214748364
Each column is one digit position. The top row is the digits of x still to read, and a digit is cleared after it is read. The bottom row is the digits of res, in the order they were appended.
digitthe last digit of x, read by x % 10appendthe digit just added to the right end of restoo bigres when it is above INT_MAX // 10 and the next multiply would overflow
Start: x = 1534236469 and res = 0. The loop runs while x > 0.
Gotcha 1 of 3
- The trap
Gotcha 1: Checking the 32-bit limit after
res * 10 + digitMistakeres = res * 10 + digit if res > INT_MAX: return 0Fixif res > INT_MAX // 10 or (res == INT_MAX // 10 and digit > 7): return 0 res = res * 10 + digitWhat happens: In Java or C++,
resis a 32-bit integer.res * 10 + digitcan go pastINT_MAX, which is 2^31 - 1. Java then wraps the value around, and in C++ signed overflow is undefined behavior. A check after the multiply only sees the wrapped value. For x = 1534236469, the true reverse is 9646324351, and Java's wrapped value is 1056389759. That value is belowINT_MAX, so the late check lets it through. Python ints never overflow, so in Python both orders return 0. The check before the multiply is the one that works in every language.
- The number must be reversed in binary, always 32 bits wide, as in Reverse Bits (LC 190), not in base 10. See Bit Tricks
Deep Dive
Three moves: read, drop and append
A number can be taken apart and rebuilt without a string. Three moves are enough. x % 10 reads the last digit. x //= 10 drops the last digit. res = res * 10 + digit adds a digit at the right end of res.
Each loop round moves one digit from the right end of x to the right end of res. The first digit read is the last digit of x, and it becomes the first digit of res. So res holds the digits in reverse order.
Example: x = 123. Round 1 reads 3, so x = 12 and res = 3. Round 2 reads 2, so x = 1 and res = 32. Round 3 reads 1, so x = 0 and res = 321. The loop stops because x > 0 is false.
A trailing zero is handled without extra code. For x = 120, the first digit is 0, so res = 0 * 10 + 0 = 0. The next digits give res = 2 and then res = 21. The answer is 21.
Check the limit before the multiply
INT_MAX is 2147483647, and INT_MAX // 10 is 214748364. After the multiply, res * 10 + digit must not be above INT_MAX. So before the multiply, res must not be above 214748364. If res is exactly 214748364, the last digit must be at most 7.
Trace for x = 1534236469. The first nine digits give res = 964632435. This is above 214748364, so the tenth digit, 1, is never appended. The function returns 0. The true reverse is 9646324351, which does not fit in 32 bits.
The check must come first. Java and C++ use 32-bit integers. In Java, res * 10 + digit wraps around and gives 1056389759 for this input. That value is below INT_MAX, so a check after the multiply passes by mistake. In C++, signed overflow is undefined behavior. Python integers have no limit, so Python hides this problem, but the same order is correct in every language.
For a valid 32-bit input with 10 digits, the first digit is 1 or 2. That digit is the last one appended, so the test digit > 7 never fires for a valid input. It stays in the blueprint so that the rule is exact for the limit 2147483647.
Negative numbers in Python
In Python, % and // round toward minus infinity. So -7 % 10 is 3 and -7 // 10 is -1. On a negative x, the loop x //= 10 stops at -1 and never reaches 0, so the loop never ends.
The blueprint avoids this. It stores sign = -1 if x < 0 else 1 and works on x = abs(x). After the loop, res *= sign puts the sign back. For x = -123 the answer is -321.
Last, the blueprint checks INT_MIN <= res <= INT_MAX. The test before each multiply used only the positive limit, so this final check covers the negative side.
Do not reverse the digits through a string. str(-123)[::-1] is "321-", and int("321-") raises ValueError. The string version also still needs the 32-bit check.
The same moves in other orders
The three moves solve a family of problems. Only the order and the stopping rule change.
Palindrome Number (LC 9) reverses only the second half of the digits. The loop while x > rev: rev = rev * 10 + x % 10; x //= 10 stops at the middle. The number is a palindrome when x == rev or x == rev // 10. A negative number, or a number that ends in 0 but is not 0, is rejected first. Here rev never gets larger than x, so no overflow check is needed.
String to Integer (atoi) (LC 8) parses text with the same append, res = res * 10 + digit, and the same check before the multiply. It clamps the result to the limit instead of returning 0. Plus One (LC 66) and Multiply Strings (LC 43) walk over digit arrays and carry one digit to the next.
The loop runs once per digit, so the time is O(log10 |x|), which is at most 10 rounds for a 32-bit number. The extra space is O(1).
60-Second Pitch
"I take the number apart one digit at a time. x % 10 reads the last digit, x //= 10 drops it, and res = res * 10 + digit appends it. Reading from the right and appending on the right reverses the digits. In Python, % and // round toward minus infinity, so I store the sign and work on abs(x). The risk is overflow. In a language with 32-bit integers, the multiply can already wrap, so I test res > INT_MAX // 10 before I multiply, with the extra case res == INT_MAX // 10 and digit > 7. If the test is true, I return 0. The time is O(log10 |x|), at most 10 rounds for a 32-bit number, and the space is O(1)."
Common Questions
- Why do you check
res > INT_MAX // 10before the multiply? With 32-bit integers,
res * 10 + digitcan overflow during the multiply. Java wraps the value around, and C++ has undefined behavior. A check afterwards sees the damaged value. The check before the multiply decides in advance. Ifresis below 214748364, any digit is safe. Ifresis exactly 214748364, only the digits 0 to 7 are safe. Ifresis above 214748364, no digit is safe.- Why do you work on
abs(x)and restoresignat the end? In Python,
%and//round toward minus infinity, so-7 % 10is 3 and-7 // 10is -1. A loop on a negativexnever reaches 0. Working onabs(x)avoids that, andres *= signputs the sign back.- What does
x = 120return, and why? It returns 21. The first digit read is 0, so
resstays 0. The next digits makeres = 2and thenres = 21. The reverse as text is021, and as a number that is 21.- What are the time and space complexity?
The time is O(log10 |x|), because each round removes one digit. For a 32-bit number that is at most 10 rounds. The space is
O(1), because the code keeps onlyx,res,digitandsign.- How does the same idea check a palindrome number?
Palindrome Number (LC 9) reverses only the second half. The loop
while x > revmoves digits fromxtorev. Thenx == revhandles an even number of digits, andx == rev // 10handles an odd number. Negative numbers, and numbers that end in 0 but are not 0, are rejected first.
SWE Reasoning
Spot it
- The problem builds, reverses, compares or parses a number one digit at a time (Reverse Integer (LC 7), Palindrome Number (LC 9), String to Integer (atoi) (LC 8)).
- The result must be 0, or must be clamped, when it leaves the 32-bit range.
- Converting the number to a string would work but is not allowed, or needs extra care for the sign.
- The code runs in a language with fixed-width integers, where the multiply itself can overflow.
The invariant, step by step
signis stored andx = abs(x).resis 0.- Each round reads
digit = x % 10and drops it withx //= 10. The digit moves fromxtores. - Before the append, the code tests
res > INT_MAX // 10, andres == INT_MAX // 10 and digit > 7. If the test is true,res * 10 + digitwould be aboveINT_MAX, and the function returns 0. - If the test is false,
res = res * 10 + digitis safe.resis the reverse of the digits already removed fromx. - When
xis 0, all digits have moved, andresis the reverse of the original digits. res *= signrestores the sign. The final range check returns 0 if the signed value is outside the 32-bit range.
Traps
- Checking after the multiply. In Java,
res * 10 + digithas already wrapped. Forx = 1534236469, the wrapped value is 1056389759, which is belowINT_MAX, so the late check does not fire. - Using
%and//on a negativex. In Python,-7 // 10is -1, sox != 0never becomes false and the loop never ends. Useabs(x)and applysignat the end. - Reversing through a string.
int(str(-123)[::-1])raisesValueError, because the string is"321-". - Wrong limit. Testing
res > INT_MAXinstead ofres > INT_MAX // 10does not protect the multiply. Aresof 300000000 passes that test, and thenres * 10is aboveINT_MAX.