202 lines
8.6 KiB
YAML
202 lines
8.6 KiB
YAML
title: Reverse Integer
|
|
slug: reverse-integer
|
|
difficulty: easy
|
|
leetcode_id: 7
|
|
leetcode_url: https://leetcode.com/problems/reverse-integer/
|
|
categories:
|
|
- math
|
|
patterns:
|
|
- slug: greedy
|
|
is_optimal: true
|
|
|
|
function_signature: "def reverse(x: int) -> int:"
|
|
|
|
test_cases:
|
|
visible:
|
|
- input: { x: 123 }
|
|
expected: 321
|
|
- input: { x: -123 }
|
|
expected: -321
|
|
- input: { x: 120 }
|
|
expected: 21
|
|
hidden:
|
|
- input: { x: 0 }
|
|
expected: 0
|
|
- input: { x: -120 }
|
|
expected: -21
|
|
- input: { x: 1534236469 }
|
|
expected: 0
|
|
- input: { x: -2147483648 }
|
|
expected: 0
|
|
- input: { x: 2147483647 }
|
|
expected: 0
|
|
- input: { x: 1463847412 }
|
|
expected: 2147483641
|
|
- input: { x: -1 }
|
|
expected: -1
|
|
|
|
description: |
|
|
Given a signed 32-bit integer `x`, return `x` *with its digits reversed*. If reversing `x` causes the value to go outside the signed 32-bit integer range `[-2^31, 2^31 - 1]`, then return `0`.
|
|
|
|
**Assume the environment does not allow you to store 64-bit integers (signed or unsigned).**
|
|
|
|
constraints: |
|
|
- `-2^31 <= x <= 2^31 - 1`
|
|
|
|
examples:
|
|
- input: "x = 123"
|
|
output: "321"
|
|
explanation: "The digits of 123 reversed give 321."
|
|
- input: "x = -123"
|
|
output: "-321"
|
|
explanation: "The digits of -123 reversed give -321. The negative sign is preserved."
|
|
- input: "x = 120"
|
|
output: "21"
|
|
explanation: "Trailing zeros in the original number become leading zeros after reversal and are dropped."
|
|
|
|
explanation:
|
|
intuition: |
|
|
Think of reversing an integer like reading a number backwards, digit by digit.
|
|
|
|
Imagine you have a stack of cards, each showing one digit of the number. To reverse the number, you'd pick up cards from the original stack one at a time (starting from the rightmost digit) and place them face-up in a new stack. The first card you pick becomes the most significant digit of your new number.
|
|
|
|
The key insight is that you can extract digits from the right using the modulo operator (`x % 10` gives the last digit) and build the reversed number by multiplying your accumulated result by 10 before adding each new digit.
|
|
|
|
The critical challenge is **overflow detection**. Since we cannot use 64-bit integers, we must check *before* each multiplication whether the operation would overflow the 32-bit signed integer range. This requires checking against `INT_MAX // 10` and `INT_MIN // 10` before multiplying.
|
|
|
|
approach: |
|
|
We solve this by **extracting digits from the right and building the reversed number**.
|
|
|
|
**Step 1: Handle the sign**
|
|
|
|
- We can work with the absolute value and restore the sign at the end, or handle negative numbers directly with modulo (Python's modulo handles negatives differently, so we'll track the sign separately)
|
|
|
|
|
|
|
|
**Step 2: Extract digits one by one**
|
|
|
|
- Use `digit = x % 10` to get the rightmost digit
|
|
- Use `x = x // 10` to remove that digit from the original number
|
|
- Repeat until `x` becomes `0`
|
|
|
|
|
|
|
|
**Step 3: Build the reversed number with overflow checking**
|
|
|
|
- Before multiplying `result` by 10, check if it would overflow:
|
|
- If `result > INT_MAX // 10`, multiplying would overflow
|
|
- If `result < INT_MIN // 10`, multiplying would underflow
|
|
- If `result == INT_MAX // 10` and `digit > 7`, adding the digit would overflow
|
|
- If `result == INT_MIN // 10` and `digit < -8`, adding the digit would underflow
|
|
- If safe, compute `result = result * 10 + digit`
|
|
|
|
|
|
|
|
**Step 4: Return the result**
|
|
|
|
- Return the reversed number, or `0` if overflow was detected
|
|
|
|
common_pitfalls:
|
|
- title: Ignoring Overflow
|
|
description: |
|
|
The most common mistake is forgetting to check for overflow. With 32-bit signed integers, the range is `[-2147483648, 2147483647]`.
|
|
|
|
Consider `x = 1534236469`. Reversed, this would be `9646324351`, which exceeds `INT_MAX`. Without overflow checking, you'd get undefined behaviour or incorrect results.
|
|
|
|
Always check *before* the operation that could cause overflow, not after.
|
|
wrong_approach: "Reversing without bounds checking"
|
|
correct_approach: "Check against INT_MAX // 10 before multiplying"
|
|
|
|
- title: Using 64-bit Integers
|
|
description: |
|
|
The problem explicitly states you cannot use 64-bit integers. A common "cheat" is to use a `long` or `int64_t` to hold the intermediate result and check bounds at the end.
|
|
|
|
While this works in practice, it violates the problem constraints. The correct approach is to detect potential overflow *before* it happens using only 32-bit arithmetic.
|
|
wrong_approach: "Using long/int64 for intermediate calculations"
|
|
correct_approach: "Pre-check overflow using INT_MAX // 10"
|
|
|
|
- title: Incorrect Handling of Negative Numbers
|
|
description: |
|
|
In some languages, the modulo operator behaves differently for negative numbers. For example, in C++, `-123 % 10` gives `-3`, while in Python it gives `7`.
|
|
|
|
The safest approach is to track the sign separately and work with the absolute value, then restore the sign at the end.
|
|
wrong_approach: "Assuming modulo always gives positive results"
|
|
correct_approach: "Track sign separately or understand language-specific modulo behaviour"
|
|
|
|
- title: Edge Case with INT_MIN
|
|
description: |
|
|
`INT_MIN` is `-2147483648`, but `abs(INT_MIN)` cannot be represented as a positive 32-bit integer (since `INT_MAX` is only `2147483647`).
|
|
|
|
Special handling may be needed when working with the absolute value of `INT_MIN`.
|
|
|
|
key_takeaways:
|
|
- "**Digit extraction pattern**: `x % 10` extracts the last digit, `x // 10` removes it — this pattern appears in many number manipulation problems"
|
|
- "**Overflow prevention**: Always check *before* an operation that could overflow, not after — compare against `INT_MAX // 10`"
|
|
- "**Building numbers digit by digit**: `result = result * 10 + digit` is the standard way to construct an integer from its digits"
|
|
- "**Related problems**: This technique extends to palindrome checking, digit sum problems, and number conversion tasks"
|
|
|
|
time_complexity: "O(log x). The number of digits in `x` is proportional to `log10(x)`, and we process each digit once."
|
|
space_complexity: "O(1). We only use a constant number of variables regardless of the input size."
|
|
|
|
solutions:
|
|
- approach_name: Mathematical Digit Extraction
|
|
is_optimal: true
|
|
code: |
|
|
def reverse(x: int) -> int:
|
|
INT_MAX = 2**31 - 1 # 2147483647
|
|
INT_MIN = -2**31 # -2147483648
|
|
|
|
result = 0
|
|
# Track sign and work with absolute value
|
|
sign = 1 if x >= 0 else -1
|
|
x = abs(x)
|
|
|
|
while x != 0:
|
|
# Extract the last digit
|
|
digit = x % 10
|
|
x //= 10
|
|
|
|
# Check for overflow before multiplying
|
|
# If result > INT_MAX // 10, then result * 10 will overflow
|
|
# If result == INT_MAX // 10 and digit > 7, result * 10 + digit overflows
|
|
if result > INT_MAX // 10 or (result == INT_MAX // 10 and digit > 7):
|
|
return 0
|
|
|
|
# Build the reversed number
|
|
result = result * 10 + digit
|
|
|
|
return sign * result
|
|
explanation: |
|
|
**Time Complexity:** O(log x) — We process each digit once, and the number of digits is O(log x).
|
|
|
|
**Space Complexity:** O(1) — Only a constant number of variables are used.
|
|
|
|
We extract digits from right to left using modulo and integer division, building the reversed number by multiplying by 10 and adding each digit. The key is checking for overflow *before* the multiplication to stay within 32-bit bounds.
|
|
|
|
- approach_name: String Conversion
|
|
is_optimal: false
|
|
code: |
|
|
def reverse(x: int) -> int:
|
|
INT_MAX = 2**31 - 1
|
|
INT_MIN = -2**31
|
|
|
|
# Handle sign
|
|
sign = 1 if x >= 0 else -1
|
|
x = abs(x)
|
|
|
|
# Convert to string, reverse, convert back
|
|
reversed_str = str(x)[::-1]
|
|
result = sign * int(reversed_str)
|
|
|
|
# Check bounds
|
|
if result < INT_MIN or result > INT_MAX:
|
|
return 0
|
|
|
|
return result
|
|
explanation: |
|
|
**Time Complexity:** O(log x) — String operations are proportional to the number of digits.
|
|
|
|
**Space Complexity:** O(log x) — The string representation uses space proportional to the number of digits.
|
|
|
|
This approach converts the number to a string, reverses it, and converts back. While simpler to implement, it uses extra space and arguably violates the spirit of the "no 64-bit integers" constraint since Python integers are arbitrary precision. The mathematical approach is preferred for interviews.
|