title: Check if Binary String Has at Most One Segment of Ones
slug: check-if-binary-string-has-at-most-one-segment-of-ones
difficulty: easy
leetcode_id: 1784
leetcode_url: https://leetcode.com/problems/check-if-binary-string-has-at-most-one-segment-of-ones/
categories:
  - strings
patterns:
  - two-pointers

description: |
  Given a binary string `s` **without leading zeros**, return `true` *if* `s` *contains **at most one contiguous segment of ones***. Otherwise, return `false`.

  A contiguous segment of ones means all the `1`s in the string appear consecutively without any `0`s between them.

constraints: |
  - `1 <= s.length <= 100`
  - `s[i]` is either `'0'` or `'1'`
  - `s[0]` is `'1'` (no leading zeros)

examples:
  - input: 's = "1001"'
    output: "false"
    explanation: "The ones do not form a contiguous segment. There is a '1' at index 0, then zeros, then another '1' at index 3."
  - input: 's = "110"'
    output: "true"
    explanation: "The ones form a single contiguous segment at the beginning: '11'. The trailing '0' doesn't break continuity."

explanation:
  intuition: |
    The key insight comes from understanding what the constraint "no leading zeros" means for this problem.

    Since the string **must** start with a `'1'`, all the ones in a valid string must appear at the very beginning. Think of it like this: once we see a `'0'`, we've "left" the segment of ones. If we ever see another `'1'` after that, we've found a second segment — which makes the answer `false`.

    The critical observation is that a valid string looks like `1...10...0` (some ones followed by some zeros). An invalid string has the pattern `1...10...01...1` — where a `'1'` appears **after** a `'0'`.

    This simplifies to checking for the substring `"01"` followed by any `'1'`. Even simpler: if `"01"` appears anywhere in the string, there will be a `'1'` before the `'0'` (since the string starts with `'1'`), so we just need to check if `"01"` is followed eventually by another `'1'`. The simplest check: does `"01"` appear in the string? If yes, and since we start with `'1'`, the only way to have `"01"` is if there are ones, then zeros, and since the string started with ones, any character after `"01"` that is `'1'` creates two segments.

    Actually, the simplest observation: **if the pattern "01" appears in the string, check if any '1' comes after it**. But even simpler — since `s[0] = '1'`, we just need to check if the substring `"01"` appears in `s`. If it does, the string has the form `1...01...` and that trailing part could have more ones.

    Wait, let's reconsider. The string `"110"` contains `"01"` (at positions 1-2). But the answer is `true`. So just checking for `"01"` isn't enough.

    The real insight: we need to find if **after seeing a zero, we see another one**. This is equivalent to checking if the string contains `"01"` where there's a `'1'` somewhere after it. The simplest way: check if `"01"` appears in `s`. Since `s` has no leading zeros, `"01"` can only appear after some ones. After `"01"`, if there are more ones, we have two segments. If not (like `"110"`), we don't.

    The cleanest formulation: **the string is invalid if and only if it contains the substring `"01"` and any `'1'` appears after the first occurrence of `"01"`**. This is equivalent to checking if the string contains `"01"` at any position that isn't the very end, OR if it ends with `"01"` we're fine.

    The simplest check: **Does the string contain the pattern `"01"` where the `"1"` in `"01"` is followed by anything that contains a `'1'`?** This is just: `"01"` appears and isn't at the very end with nothing after, or what follows contains a `'1'`.

    Simplest of all: **Check if `"01"` appears in the string. If so, check if there's any `'1'` after that position.** This can be simplified to: **the string is invalid if and only if it contains the substring `"01"` AND the character after `"01"` (or later) is a `'1'`**.

    Actually the cleanest solution: **A string has two segments if and only if it contains `"01"` where a `'1'` appears anywhere after the `'0'` in `"01"`.** Since the string starts with `'1'`, this is equivalent to checking if the string contains `"01"` followed by any `'1'`. This is just: **does `"01"` appear anywhere except right before only zeros (or end of string)?**

    The trick is realising that the string format `1+0+` (one or more ones, followed by zero or more zeros) is the only valid format. Any `'1'` appearing after a `'0'` is invalid. So: **return `"01"` not in `s`**? No, `"110"` has `"01"` at the end and is valid!

    Final insight: Since the string cannot have leading zeros (starts with `'1'`), having one segment of ones means all ones are at the start. **The string is valid if and only if once we see a `'0'`, we never see a `'1'` again.** This is the pattern `"01"` followed by `'1'` — the substring `"01"` itself is okay, but not if followed by more ones.

    The simplest code: check if `"01"` appears anywhere. If the part after the `"01"` contains a `'1'`, return `false`. Since we only care about the first `"01"`, we can just check: **does the string contain the substring `"01"` where a `'1'` follows it?** This is equivalent to `"01"` being present AND not being the last two characters (since after them comes nothing or only zeros).

    Actually — just check if `'1'` appears after ANY `'0'`. If we ever see a `'0'` followed eventually by a `'1'`, that's two segments. This is precisely the check: **return `"01"` not in s** BUT we need `"01"` where the `'1'` is after the `'0'`. Wait, `"01"` is literally `'0'` followed by `'1'`.

    So the answer is: **return `"01"` not in s**. Let's verify:
    - `"1001"`: contains `"01"` at position 2-3? Actually position 2 is `'0'`, position 3 is `'1'`. Yes, `"01"` is at index 2. So return `false`. Correct!
    - `"110"`: contains `"01"` at position 1-2. So return `false`. But expected is `true`! So this approach is wrong.

    Let me re-examine. `"110"` has chars `'1'` at 0, `'1'` at 1, `'0'` at 2. So we have `"11"` then `"10"`. There's no `"01"` substring. So `"01" not in "110"` is `True`. Return `True`. Correct!

    Let me re-check `"1001"`: chars are `'1'`, `'0'`, `'0'`, `'1'`. The substrings of length 2 are `"10"`, `"00"`, `"01"`. Yes, `"01"` appears! So return `False`. Correct!

    The solution is simply: **return `"01"` not in s**.

  approach: |
    We solve this using a **Substring Check** approach:

    **Step 1: Understand the pattern**

    - A binary string with no leading zeros starts with `'1'`
    - For all ones to be contiguous, they must all be at the beginning
    - The valid pattern is: `1...10...0` (ones followed by zeros)
    - The invalid pattern is: `1...10...01` (a `'1'` appearing after a `'0'`)

    &nbsp;

    **Step 2: Identify the key insight**

    - If a `'0'` is ever followed directly by a `'1'` (the substring `"01"`), there are multiple segments
    - If `"01"` never appears, all ones are contiguous at the start

    &nbsp;

    **Step 3: Check for the pattern**

    - Simply check if the substring `"01"` exists in `s`
    - If it does, return `false` (multiple segments)
    - If it doesn't, return `true` (at most one segment)

    &nbsp;

    This works because `"01"` appearing means we transitioned from zeros back to ones, which is only possible if there's a gap in the ones.

  common_pitfalls:
    - title: Counting Segments with State Machine
      description: |
        A common over-complication is to build a state machine or counter to track "entering" and "leaving" segments of ones.

        While this works, it's more complex than necessary. The substring check `"01" in s` captures the exact condition in one operation.
      wrong_approach: "Tracking state transitions and counting segments"
      correct_approach: "Check for '01' substring"

    - title: Misunderstanding the Leading Zero Constraint
      description: |
        Some solutions forget that `s[0]` is guaranteed to be `'1'`. This constraint is crucial — it means we don't need to handle cases like `"0110"`.

        Without this constraint, we'd need additional logic. With it, any `"01"` substring definitively indicates multiple segments.
      wrong_approach: "Adding unnecessary checks for leading zeros"
      correct_approach: "Trust the constraint that s[0] = '1'"

    - title: Off-by-One in Manual Iteration
      description: |
        When manually iterating, it's easy to make off-by-one errors when checking adjacent characters.

        ```python
        # Wrong: might miss the last pair
        for i in range(len(s) - 1):  # Correct, but easy to write range(len(s)) by mistake
        ```

        Using the built-in substring check avoids these issues entirely.

  key_takeaways:
    - "**Pattern recognition**: Translate the problem into a simple substring or pattern check when possible"
    - "**Use constraints**: The 'no leading zeros' constraint simplifies the problem significantly"
    - "**Built-in operations**: Python's `in` operator for substrings is both readable and efficient"
    - "**Similar problems**: This pattern of checking for forbidden substrings applies to many string validation problems"

  time_complexity: "O(n). The substring check `\"01\" in s` scans the string once."
  space_complexity: "O(1). We only perform a containment check without allocating additional data structures."

solutions:
  - approach_name: Substring Check
    is_optimal: true
    code: |
      def check_ones_segment(s: str) -> bool:
          # If '01' appears, a '1' comes after a '0' — meaning multiple segments
          # If '01' doesn't appear, all '1's are contiguous at the start
          return "01" not in s
    explanation: |
      **Time Complexity:** O(n) — Single pass through the string for substring search.

      **Space Complexity:** O(1) — No additional space used.

      This elegant one-liner leverages the constraint that the string has no leading zeros. Since the string starts with `'1'`, the only way to have the substring `"01"` is if there's a `'0'` followed by a `'1'` — which means the ones are not contiguous.

  - approach_name: Linear Scan with Flag
    is_optimal: false
    code: |
      def check_ones_segment(s: str) -> bool:
          seen_zero = False

          for char in s:
              if char == '0':
                  # We've left the initial segment of ones
                  seen_zero = True
              elif seen_zero:
                  # Found a '1' after seeing a '0' — two segments
                  return False

          # Never found a '1' after a '0'
          return True
    explanation: |
      **Time Complexity:** O(n) — Single pass through the string.

      **Space Complexity:** O(1) — Only one boolean flag used.

      This approach explicitly tracks whether we've seen a `'0'`. Once we have, any subsequent `'1'` means there are multiple segments. While correct and efficient, the substring check approach is more concise.
