title: Binary Prefix Divisible By 5
slug: binary-prefix-divisible-by-5
difficulty: easy
leetcode_id: 1018
leetcode_url: https://leetcode.com/problems/binary-prefix-divisible-by-5/
categories:
  - arrays
  - math
patterns:
  - prefix-sum

description: |
  You are given a binary array `nums` (**0-indexed**).

  We define `x_i` as the number whose binary representation is the subarray `nums[0..i]` (from most-significant-bit to least-significant-bit).

  For example, if `nums = [1,0,1]`, then `x_0 = 1`, `x_1 = 2`, and `x_2 = 5`.

  Return *an array of booleans* `answer` *where* `answer[i]` *is* `true` *if* `x_i` *is divisible by* `5`.

constraints: |
  - `1 <= nums.length <= 10^5`
  - `nums[i]` is either `0` or `1`

examples:
  - input: "nums = [0,1,1]"
    output: "[true, false, false]"
    explanation: "The input numbers in binary are 0, 01, 011; which are 0, 1, and 3 in base-10. Only the first number is divisible by 5, so answer[0] is true."
  - input: "nums = [1,1,1]"
    output: "[false, false, false]"
    explanation: "The binary numbers are 1, 11, 111; which are 1, 3, and 7 in base-10. None are divisible by 5."
  - input: "nums = [1,0,1,0]"
    output: "[false, false, true, false]"
    explanation: "The binary numbers are 1, 10, 101, 1010; which are 1, 2, 5, and 10 in base-10. The values 5 and 10 are divisible by 5, but 10 appears at index 3, so answer = [false, false, true, false]."

explanation:
  intuition: |
    Imagine you're reading a binary number digit by digit, from left to right. Each time you read a new digit, you're essentially building up a larger number.

    Think of it like this: if you have the number `5` (binary `101`) and you append a `0`, you get `1010` which is `10` in decimal. Appending a digit doubles the previous number and adds the new bit. Mathematically: `new_number = old_number * 2 + new_bit`.

    The key insight is that we don't need to track the actual number — it could grow astronomically large (up to 2<sup>100000</sup>). Instead, we only care about **divisibility by 5**, which means we only need to track the **remainder when divided by 5**.

    This works because of **modular arithmetic**: if we know the remainder of `old_number % 5`, we can compute `new_number % 5` directly as `(old_number * 2 + new_bit) % 5`. The intermediate large numbers never need to be stored.

  approach: |
    We solve this using a **Running Remainder** approach:

    **Step 1: Initialise variables**

    - `current`: Set to `0` to represent the running number mod 5
    - `result`: An empty list to collect our boolean answers

    &nbsp;

    **Step 2: Iterate through the binary array**

    - For each bit in `nums`, update `current` using the formula: `current = (current * 2 + bit) % 5`
    - This simulates "shifting left and adding the new bit" while keeping only the remainder
    - Append `True` to `result` if `current == 0`, otherwise append `False`

    &nbsp;

    **Step 3: Return the result**

    - Return the `result` list containing booleans for each prefix

    &nbsp;

    This approach works because `(a * 2 + b) % 5 = ((a % 5) * 2 + b) % 5`. We maintain the invariant that `current` always holds `x_i % 5`.

  common_pitfalls:
    - title: Computing the Actual Binary Number
      description: |
        A naive approach might try to build the actual integer value at each step:

        ```python
        num = int(''.join(map(str, nums[:i+1])), 2)
        ```

        With `nums.length <= 10^5`, the binary number can have 100,000 digits. This number is astronomically large (approximately 2<sup>100000</sup>) and will cause **memory issues** and **timeout errors**.

        Instead, use modular arithmetic to track only the remainder.
      wrong_approach: "Converting binary subarray to integer"
      correct_approach: "Track running remainder mod 5"

    - title: Forgetting to Apply Modulo After Each Step
      description: |
        If you compute `current = current * 2 + bit` without taking `% 5`, the value will still overflow (in languages with fixed-size integers) or grow unnecessarily large.

        Always apply `% 5` at each step: `current = (current * 2 + bit) % 5`.
      wrong_approach: "Accumulating without modulo"
      correct_approach: "Apply % 5 after each update"

    - title: Off-by-One in Understanding the Prefix
      description: |
        The prefix `x_i` includes `nums[0]` through `nums[i]` inclusive. Make sure you're checking divisibility at the right moment — after incorporating the i<sup>th</sup> bit, not before.

  key_takeaways:
    - "**Modular arithmetic** allows you to track divisibility without storing huge numbers"
    - "**Building numbers bit by bit**: `new = old * 2 + bit` is the fundamental operation for constructing binary numbers left-to-right"
    - "**Property preservation**: If you only care about a property (like divisibility), you may not need the full value"
    - "**Pattern recognition**: This technique applies to any divisibility check on incrementally built numbers"

  time_complexity: "O(n). We traverse the array once, performing constant-time arithmetic at each step."
  space_complexity: "O(n). We store the result array of length `n`. The running remainder uses O(1) extra space."

solutions:
  - approach_name: Running Remainder
    is_optimal: true
    code: |
      def prefixes_div_by5(nums: list[int]) -> list[bool]:
          # Track the current number mod 5
          current = 0
          result = []

          for bit in nums:
              # Shift left (multiply by 2) and add new bit, keep only remainder
              current = (current * 2 + bit) % 5
              # Check if current prefix is divisible by 5
              result.append(current == 0)

          return result
    explanation: |
      **Time Complexity:** O(n) — Single pass through the array.

      **Space Complexity:** O(n) — Output array of size n; O(1) auxiliary space.

      We use modular arithmetic to track divisibility without computing the actual (potentially huge) binary numbers. At each step, `current` holds the value of the prefix modulo 5.

  - approach_name: Brute Force (Convert to Integer)
    is_optimal: false
    code: |
      def prefixes_div_by5(nums: list[int]) -> list[bool]:
          result = []

          for i in range(len(nums)):
              # Build binary string from prefix
              binary_str = ''.join(str(b) for b in nums[:i+1])
              # Convert to integer
              num = int(binary_str, 2)
              # Check divisibility
              result.append(num % 5 == 0)

          return result
    explanation: |
      **Time Complexity:** O(n^2) — For each of n prefixes, we build a string of length up to n.

      **Space Complexity:** O(n) — The binary string can grow up to length n.

      This approach works for small inputs but fails on large arrays due to the enormous numbers involved. With `n = 10^5`, the final number has 100,000 binary digits — far too large to handle efficiently. Included to illustrate why modular arithmetic is essential.
