title: Base 7
slug: base-7
difficulty: easy
leetcode_id: 504
leetcode_url: https://leetcode.com/problems/base-7/
categories:
  - strings
  - math
patterns:
  - greedy

function_signature: "def convert_to_base7(num: int) -> str:"

test_cases:
  visible:
    - input: { num: 100 }
      expected: "202"
    - input: { num: -7 }
      expected: "-10"
  hidden:
    - input: { num: 0 }
      expected: "0"
    - input: { num: 7 }
      expected: "10"
    - input: { num: 1 }
      expected: "1"
    - input: { num: -1 }
      expected: "-1"
    - input: { num: 49 }
      expected: "100"
    - input: { num: -100 }
      expected: "-202"

description: |
  Given an integer `num`, return *a string of its **base 7** representation*.

constraints: |
  - `-10^7 <= num <= 10^7`

examples:
  - input: "num = 100"
    output: "202"
    explanation: "100 in base 10 equals 2*49 + 0*7 + 2*1 = 202 in base 7."
  - input: "num = -7"
    output: "-10"
    explanation: "-7 in base 10 equals -1*7 + 0*1 = -10 in base 7."

explanation:
  intuition: |
    Think of how we normally write numbers in base 10. The number 345 means 3 hundreds + 4 tens + 5 ones, or `3*10^2 + 4*10^1 + 5*10^0`. Each digit represents how many of that power of 10 we have.

    Converting to base 7 works the same way, but with powers of 7 instead. We need to figure out how many 49s (7^2), how many 7s (7^1), and how many 1s (7^0) make up our number.

    The key insight is that **repeatedly dividing by 7 and collecting remainders** gives us the digits from right to left. When you divide a number by 7:
    - The **remainder** tells you the rightmost digit (the "ones" place in base 7)
    - The **quotient** represents what's left to convert for the higher digits

    For example, with `num = 100`:
    - `100 % 7 = 2` (rightmost digit), `100 // 7 = 14` (continue with this)
    - `14 % 7 = 0` (middle digit), `14 // 7 = 2` (continue with this)
    - `2 % 7 = 2` (leftmost digit), `2 // 7 = 0` (done!)
    - Reading remainders in reverse: **202**

  approach: |
    We solve this using **Repeated Division**:

    **Step 1: Handle the special case**

    - If `num` is `0`, return `"0"` immediately
    - This avoids an empty result from the main loop

    &nbsp;

    **Step 2: Handle the sign**

    - If `num` is negative, remember this fact and work with the absolute value
    - We'll prepend the minus sign at the end

    &nbsp;

    **Step 3: Repeatedly divide by 7**

    - While `num > 0`:
      - Calculate `num % 7` to get the current digit
      - Prepend this digit to your result (or append and reverse later)
      - Update `num = num // 7` to move to the next higher digit

    &nbsp;

    **Step 4: Add the sign and return**

    - If the original number was negative, prepend `"-"` to the result
    - Return the final string

  common_pitfalls:
    - title: Forgetting the Zero Case
      description: |
        If `num = 0`, the while loop `while num > 0` never executes, leaving you with an empty string.

        You must handle `num = 0` as a special case and return `"0"` directly.
      wrong_approach: "Relying on the loop to handle zero"
      correct_approach: "Check for zero before entering the loop"

    - title: Incorrect Sign Handling
      description: |
        In Python, the modulo operator with negative numbers can give unexpected results. For example, `-7 % 7 = 0` in Python, but the division `-7 // 7 = -1` (floor division).

        To avoid confusion, convert to absolute value first, then add the minus sign at the end.
      wrong_approach: "Performing modulo on negative numbers directly"
      correct_approach: "Use abs(num) and track the sign separately"

    - title: Building the String in Wrong Order
      description: |
        The digits come out in reverse order (least significant first). If you append each digit, you'll need to reverse at the end.

        Alternatively, prepend each digit to build the string in the correct order from the start.
      wrong_approach: "Appending digits without reversing"
      correct_approach: "Either prepend digits or reverse at the end"

  key_takeaways:
    - "**Base conversion pattern**: Repeated division by the target base, collecting remainders, gives digits from least to most significant"
    - "**Sign handling**: Work with absolute values and track sign separately to avoid edge cases with negative modulo operations"
    - "**Generalises to any base**: This same algorithm works for converting to binary, octal, hex, or any base — just change the divisor"
    - "**Foundation for encoding problems**: Understanding base conversion helps with problems involving bit manipulation, encoding schemes, and number representations"

  time_complexity: "O(log_7(n)). Each division reduces the number by a factor of 7, so we perform approximately log base 7 of n iterations."
  space_complexity: "O(log_7(n)). The output string has one character per digit, which is proportional to log base 7 of n."

solutions:
  - approach_name: Repeated Division
    is_optimal: true
    code: |
      def convert_to_base7(num: int) -> str:
          # Special case: zero is just "0"
          if num == 0:
              return "0"

          # Track if negative, then work with absolute value
          negative = num < 0
          num = abs(num)

          digits = []
          while num > 0:
              # Get the rightmost digit in base 7
              digits.append(str(num % 7))
              # Move to the next higher digit
              num //= 7

          # Digits are collected in reverse order, so reverse them
          result = ''.join(reversed(digits))

          # Add minus sign if original was negative
          return '-' + result if negative else result
    explanation: |
      **Time Complexity:** O(log_7(n)) — We divide by 7 until the number becomes 0.

      **Space Complexity:** O(log_7(n)) — The result string contains one digit per division.

      We repeatedly extract the least significant digit using modulo 7, then shift right by dividing by 7. The digits come out in reverse order, so we reverse at the end.

  - approach_name: Recursion
    is_optimal: false
    code: |
      def convert_to_base7(num: int) -> str:
          # Base case: single digit
          if num >= 0 and num < 7:
              return str(num)
          # Handle negatives
          if num < 0:
              return '-' + convert_to_base7(-num)

          # Recursive case: higher digits + current digit
          return convert_to_base7(num // 7) + str(num % 7)
    explanation: |
      **Time Complexity:** O(log_7(n)) — Same number of operations as iterative.

      **Space Complexity:** O(log_7(n)) — Call stack depth plus string concatenation.

      The recursive approach naturally builds digits from most significant to least significant. The base case handles single digits (0-6), and the recursive case processes the quotient first before appending the current remainder. While elegant, this uses additional stack space.

  - approach_name: Built-in (Python-specific)
    is_optimal: false
    code: |
      def convert_to_base7(num: int) -> str:
          # Handle negative numbers
          if num < 0:
              return '-' + convert_to_base7(-num)
          # Handle zero
          if num == 0:
              return "0"

          # Use divmod for cleaner extraction
          result = []
          while num:
              num, remainder = divmod(num, 7)
              result.append(str(remainder))
          return ''.join(reversed(result))
    explanation: |
      **Time Complexity:** O(log_7(n)) — Same as other approaches.

      **Space Complexity:** O(log_7(n)) — Same as other approaches.

      This version uses Python's `divmod()` function which returns both quotient and remainder in one operation. While not fundamentally different, it's a cleaner idiom that some interviewers appreciate. Note that Python has no built-in for arbitrary base conversion, so the algorithm remains the same.
