title: Binary String With Substrings Representing 1 To N
slug: binary-string-with-substrings-representing-1-to-n
difficulty: medium
leetcode_id: 1016
leetcode_url: https://leetcode.com/problems/binary-string-with-substrings-representing-1-to-n/
categories:
  - strings
  - math
patterns:
  - slug: sliding-window
    is_optimal: true

function_signature: "def query_string(s: str, n: int) -> bool:"

test_cases:
  visible:
    - input: { s: "0110", n: 3 }
      expected: true
    - input: { s: "0110", n: 4 }
      expected: false
  hidden:
    - input: { s: "1", n: 1 }
      expected: true
    - input: { s: "0", n: 1 }
      expected: false
    - input: { s: "110101011011000011011111000000", n: 15 }
      expected: false
    - input: { s: "1111000110110111011100011", n: 12 }
      expected: true
    - input: { s: "10101010101010", n: 7 }
      expected: false
    - input: { s: "1010110001010100111010011110100101110", n: 20 }
      expected: false

description: |
  Given a binary string `s` and a positive integer `n`, return `true` *if the binary representation of all the integers in the range* `[1, n]` *are **substrings** of* `s`*, or* `false` *otherwise*.

  A **substring** is a contiguous sequence of characters within a string.

constraints: |
  - `1 <= s.length <= 1000`
  - `s[i]` is either `'0'` or `'1'`
  - `1 <= n <= 10^9`

examples:
  - input: 's = "0110", n = 3'
    output: "true"
    explanation: "The binary representations are: 1 = '1', 2 = '10', 3 = '11'. All of these are substrings of '0110': '1' appears at index 1, '10' appears at index 2, '11' appears at index 1."
  - input: 's = "0110", n = 4'
    output: "false"
    explanation: "The binary representation of 4 is '100', which is not a substring of '0110'."

explanation:
  intuition: |
    At first glance, this problem seems daunting: how can we possibly check all numbers from 1 to n when n can be as large as 10<sup>9</sup>?

    The key insight is a **length constraint**. A string of length `m` can contain at most `m` substrings of any given length `k` (specifically, `m - k + 1` substrings). Since our string has at most 1000 characters, it can contain at most about 1000 distinct substrings of each length.

    Think of it like this: if you need to fit all binary representations from 1 to n into a string of length 1000, there's a natural limit. The binary representation of n has roughly `log2(n)` digits. For n = 10<sup>9</sup>, that's about 30 digits. A string of length 1000 can have at most ~970 substrings of length 30, ~971 substrings of length 29, etc.

    This means if n is too large relative to the string length, we can immediately return `false`. In practice, if n exceeds roughly 2000-3000, the string simply cannot contain enough distinct substrings. This transforms a seemingly impossible O(n) problem into a very manageable one.

    **Another critical observation**: if a number k appears as a substring, then `k/2` (integer division) also appears. Why? Because `k/2` in binary is just k with the last bit removed. If "10110" is a substring, then "1011" is too (it's the prefix). This means we only need to check the **upper half** of the range `[n/2 + 1, n]`, since the lower half is automatically covered!

  approach: |
    We solve this using a **String Containment Check with Early Termination**:

    **Step 1: Handle the length constraint**

    - If the string is too short to possibly contain all required substrings, we could return `false` early
    - In practice, we let the iteration handle this naturally since it will fail quickly

    &nbsp;

    **Step 2: Check only the upper half of the range**

    - Instead of checking all numbers from 1 to n, we only check from `n // 2 + 1` to `n`
    - This is because if binary(k) exists as substring, binary(k // 2) also exists (it's a prefix)
    - This optimization cuts our work in half

    &nbsp;

    **Step 3: Iterate and check containment**

    - For each number `i` in the range `[n // 2 + 1, n]`:
      - Convert `i` to its binary representation (without the '0b' prefix)
      - Check if this binary string is a substring of `s`
      - If any number is not found, immediately return `false`

    &nbsp;

    **Step 4: Return the result**

    - If all numbers in the upper half are found, return `true`
    - The lower half is guaranteed to exist due to the prefix property

  common_pitfalls:
    - title: Checking All Numbers From 1 to N
      description: |
        A naive approach might try to check every number from 1 to n:

        ```python
        for i in range(1, n + 1):
            if bin(i)[2:] not in s:
                return False
        ```

        With n up to 10<sup>9</sup>, this would require a billion iterations. Even though each `in` check is O(m) where m is the string length, this is far too slow.

        The key insight is that we only need to check the upper half `[n/2 + 1, n]` because smaller numbers are automatically covered as prefixes.
      wrong_approach: "Check all n numbers"
      correct_approach: "Only check numbers in [n/2 + 1, n]"

    - title: Ignoring String Length Constraints
      description: |
        A string of length 1000 can only contain about 1000 distinct substrings of any particular length. If n requires more distinct substrings than the string can possibly hold, the answer is automatically `false`.

        For example, if n = 10000, we'd need binary strings of length up to 14 bits. But a 1000-character string can only have ~987 substrings of length 14. Since we need ~5000 distinct numbers in just the upper half, it's impossible.

        In practice, the iteration will fail quickly anyway, but understanding this constraint helps explain why the problem is tractable.
      wrong_approach: "Assume any n is possible"
      correct_approach: "Recognize string length limits the maximum feasible n"

    - title: Including the '0b' Prefix in Binary Conversion
      description: |
        Python's `bin()` function returns strings like `'0b101'` for the number 5. If you forget to strip the `'0b'` prefix with `bin(i)[2:]`, your substring checks will fail.

        For example, checking if `'0b11'` is in `'0110'` returns `False`, but checking if `'11'` is in `'0110'` returns `True`.
      wrong_approach: "Use bin(i) directly"
      correct_approach: "Use bin(i)[2:] to strip the prefix"

  key_takeaways:
    - "**Leverage mathematical properties**: The prefix relationship between binary(k) and binary(k/2) cuts the search space in half"
    - "**Consider physical constraints**: A finite string has a limited number of substrings, which bounds the maximum n that's feasible"
    - "**Early termination**: Return `false` as soon as any required substring is missing"
    - "**This pattern appears in coverage problems**: Checking if a set of items exists within a container, where relationships between items can reduce the search space"

  time_complexity: "O(n * m) in the worst case, where m is the string length. However, due to the upper-half optimization, we only check n/2 numbers, and each check is O(m). In practice, for large n, the algorithm fails quickly due to string length constraints."
  space_complexity: "O(log n). We create binary string representations of each number, which have length O(log n)."

solutions:
  - approach_name: Upper Half Check
    is_optimal: true
    code: |
      def query_string(s: str, n: int) -> bool:
          # Only check upper half: if k is found, k//2 is also found (prefix)
          for i in range(n, n // 2, -1):
              # Convert to binary without '0b' prefix
              binary_rep = bin(i)[2:]
              # Check if this binary representation is a substring
              if binary_rep not in s:
                  return False
          return True
    explanation: |
      **Time Complexity:** O(n/2 * m) where m is the string length. We check at most n/2 numbers, and each substring check is O(m).

      **Space Complexity:** O(log n) for storing the binary representation of each number.

      We iterate from n down to n/2 + 1, checking if each number's binary representation exists in s. Due to the prefix property of binary numbers, finding all numbers in the upper half guarantees all numbers in the lower half exist too.

  - approach_name: Brute Force (All Numbers)
    is_optimal: false
    code: |
      def query_string(s: str, n: int) -> bool:
          # Check every number from 1 to n
          for i in range(1, n + 1):
              # Convert to binary without '0b' prefix
              binary_rep = bin(i)[2:]
              # Check if this binary representation is a substring
              if binary_rep not in s:
                  return False
          return True
    explanation: |
      **Time Complexity:** O(n * m) where m is the string length. We check all n numbers.

      **Space Complexity:** O(log n) for storing the binary representation.

      This naive approach checks every number from 1 to n. While correct, it's twice as slow as the optimized version since it doesn't exploit the prefix property. For very large n, this would be prohibitively slow, though the string length constraint means the loop typically terminates early anyway.
