title: Reverse Integer
slug: reverse-integer
difficulty: easy
leetcode_id: 7
leetcode_url: https://leetcode.com/problems/reverse-integer/
categories:
  - math
patterns:
  - greedy

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)

    &nbsp;

    **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`

    &nbsp;

    **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`

    &nbsp;

    **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.
