title: Check if Number is a Sum of Powers of Three
slug: check-if-number-is-a-sum-of-powers-of-three
difficulty: medium
leetcode_id: 1780
leetcode_url: https://leetcode.com/problems/check-if-number-is-a-sum-of-powers-of-three/
categories:
  - math
patterns:
  - slug: greedy
    is_optimal: true

function_signature: "def check_powers_of_three(n: int) -> bool:"

test_cases:
  visible:
    - input: { n: 12 }
      expected: true
    - input: { n: 91 }
      expected: true
    - input: { n: 21 }
      expected: false
  hidden:
    - input: { n: 1 }
      expected: true
    - input: { n: 3 }
      expected: true
    - input: { n: 4 }
      expected: true
    - input: { n: 2 }
      expected: false
    - input: { n: 6 }
      expected: false
    - input: { n: 9 }
      expected: true
    - input: { n: 10 }
      expected: true

description: |
  Given an integer `n`, return `true` *if it is possible to represent* `n` *as the sum of distinct powers of three*. Otherwise, return `false`.

  An integer `y` is a power of three if there exists an integer `x` such that `y == 3^x`.

constraints: |
  - `1 <= n <= 10^7`

examples:
  - input: "n = 12"
    output: "true"
    explanation: "12 = 3^1 + 3^2 = 3 + 9"
  - input: "n = 91"
    output: "true"
    explanation: "91 = 3^0 + 3^2 + 3^4 = 1 + 9 + 81"
  - input: "n = 21"
    output: "false"
    explanation: "21 cannot be represented as a sum of distinct powers of three."

explanation:
  intuition: |
    Think of this problem like converting a number to a different base system, specifically **base 3 (ternary)**.

    In our familiar decimal system, we use digits 0-9. In binary (base 2), we use 0-1. In ternary (base 3), we use digits 0, 1, and 2. Each position represents a power of 3: the rightmost position is 3^0 = 1, the next is 3^1 = 3, then 3^2 = 9, and so on.

    Here's the key insight: when we represent `n` in base 3, if all digits are either **0 or 1**, then `n` can be written as a sum of distinct powers of three. Why? Because a digit of 1 in position `i` means we include 3^i in our sum, and a digit of 0 means we don't. Each power of three is used at most once.

    However, if any digit is **2**, that means we need to use some power of three *twice* in our sum, which violates the "distinct" requirement. For example, 21 in base 3 is `210` (2×9 + 1×3 + 0×1), meaning we'd need to use 3^2 = 9 twice — not allowed!

    So the problem reduces to: **convert `n` to base 3 and check if all digits are 0 or 1**.

  approach: |
    We solve this using **Ternary (Base-3) Digit Checking**:

    **Step 1: Repeatedly extract the last digit in base 3**

    - Use `n % 3` to get the rightmost digit in base 3
    - If this digit is 2, immediately return `false`
    - A digit of 2 means we'd need to use that power of 3 twice

    &nbsp;

    **Step 2: Remove the last digit**

    - Use integer division `n //= 3` to remove the digit we just checked
    - This shifts all remaining digits one position to the right

    &nbsp;

    **Step 3: Repeat until n becomes 0**

    - Continue the loop while `n > 0`
    - If we check all digits without finding a 2, return `true`

    &nbsp;

    This is essentially converting `n` to base 3 and validating each digit as we go, without storing the full representation.

  common_pitfalls:
    - title: Trying All Combinations of Powers
      description: |
        A brute force approach might try to enumerate all possible subsets of powers of 3 up to `n` and check if any subset sums to `n`.

        With `n <= 10^7`, we have up to 15 powers of 3 (since 3^15 > 10^7). Checking all 2^15 = 32,768 subsets is technically feasible but unnecessary and much slower than the O(log n) ternary approach.
      wrong_approach: "Enumerate all subsets of powers of 3"
      correct_approach: "Check base-3 representation for digit 2"

    - title: Forgetting Why Digit 2 Fails
      description: |
        It's important to understand *why* a digit of 2 means the answer is false. If the base-3 representation has a 2 in position `i`, that means `n` contains `2 × 3^i` as part of its decomposition.

        Since we can only use each power of 3 at most once (distinct), we cannot represent `2 × 3^i` as a sum of distinct powers. For instance, `2 × 9 = 18` cannot be written as a sum of distinct powers of 3 that equals 18 — we'd need 9 + 9, but that uses 9 twice.
      wrong_approach: "Not understanding the connection to base-3"
      correct_approach: "Recognise that ternary digits > 1 require repeated powers"

    - title: Integer Overflow with Large Powers
      description: |
        If you precompute all powers of 3 up to `n`, be careful not to overflow. In Python this isn't an issue, but in languages like C++ or Java, 3^20 exceeds 32-bit integer limits.

        The iterative modulo approach avoids this entirely since we only work with values up to `n`.
      wrong_approach: "Precomputing large powers without overflow checks"
      correct_approach: "Use iterative n % 3 and n // 3 approach"

  key_takeaways:
    - "**Base conversion insight**: Many problems involving sums of distinct powers can be solved by examining the number in that base"
    - "**Ternary representation**: A number is a sum of distinct powers of 3 if and only if its base-3 representation contains only 0s and 1s"
    - "**Pattern recognition**: This same logic applies to powers of any base — e.g., all positive integers are sums of distinct powers of 2 (binary has only 0s and 1s by definition)"
    - "**Efficiency through number theory**: Converting a brute force subset problem into a simple digit-checking problem reduces complexity dramatically"

  time_complexity: "O(log n). We divide `n` by 3 in each iteration, so we process at most log_3(n) digits."
  space_complexity: "O(1). We only use a single variable to track `n` as we modify it."

solutions:
  - approach_name: Ternary Digit Check
    is_optimal: true
    code: |
      def check_powers_of_three(n: int) -> bool:
          # Check each digit in base-3 representation
          while n > 0:
              # Get the rightmost digit in base 3
              if n % 3 == 2:
                  # Digit 2 means we'd need to use a power twice
                  return False
              # Remove the digit we just checked
              n //= 3

          # All digits were 0 or 1
          return True
    explanation: |
      **Time Complexity:** O(log n) — We divide by 3 each iteration, processing log_3(n) digits.

      **Space Complexity:** O(1) — Only uses the input variable.

      We convert `n` to base 3 on the fly, checking each digit. If any digit equals 2, we need that power of 3 twice, which violates the distinct requirement. If all digits are 0 or 1, the sum is valid.

  - approach_name: Greedy Subtraction
    is_optimal: false
    code: |
      def check_powers_of_three(n: int) -> bool:
          # Find the largest power of 3 <= n
          power = 1
          while power * 3 <= n:
              power *= 3

          # Greedily subtract powers of 3
          while n > 0 and power > 0:
              if power <= n:
                  n -= power
              power //= 3

          return n == 0
    explanation: |
      **Time Complexity:** O(log n) — Two passes through powers of 3.

      **Space Complexity:** O(1) — Only tracking `power` and `n`.

      We greedily subtract the largest possible power of 3 at each step, using each power at most once. If we reduce `n` to 0, the answer is true. This is equivalent to the ternary approach but less elegant — it's harder to see why it works.

  - approach_name: Subset Sum with Powers
    is_optimal: false
    code: |
      def check_powers_of_three(n: int) -> bool:
          # Generate all powers of 3 up to n
          powers = []
          power = 1
          while power <= n:
              powers.append(power)
              power *= 3

          # Use recursion to check if any subset sums to n
          def can_sum(index: int, remaining: int) -> bool:
              if remaining == 0:
                  return True
              if remaining < 0 or index == len(powers):
                  return False
              # Include or exclude current power
              return (can_sum(index + 1, remaining - powers[index]) or
                      can_sum(index + 1, remaining))

          return can_sum(0, n)
    explanation: |
      **Time Complexity:** O(2^k) where k = log_3(n) — potentially checking all subsets.

      **Space Complexity:** O(k) — recursion depth and powers array.

      This brute force approach tries all combinations of powers of 3. While it works for the given constraints (k <= 15), it's much slower than the O(log n) ternary approach. Included to show the connection to subset sum problems.
