title: Binary Gap
slug: binary-gap
difficulty: easy
leetcode_id: 868
leetcode_url: https://leetcode.com/problems/binary-gap/
categories:
  - math
patterns:
  - two-pointers

description: |
  Given a positive integer `n`, find and return *the **longest distance** between any two **adjacent*** `1`*'s in the binary representation of* `n`. If there are no two adjacent `1`'s, return `0`.

  Two `1`'s are **adjacent** if there are only `0`'s separating them (possibly no `0`'s). The **distance** between two `1`'s is the absolute difference between their bit positions. For example, the two `1`'s in `"1001"` have a distance of 3.

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

examples:
  - input: "n = 22"
    output: "2"
    explanation: "22 in binary is '10110'. The first adjacent pair of 1's has a distance of 2, and the second pair has a distance of 1. The answer is the largest of these distances, which is 2."
  - input: "n = 8"
    output: "0"
    explanation: "8 in binary is '1000'. There is only one 1-bit, so there are no adjacent pairs of 1's."
  - input: "n = 5"
    output: "2"
    explanation: "5 in binary is '101'. The two 1's are separated by one 0, giving a distance of 2."

explanation:
  intuition: |
    Imagine the binary representation of a number as a row of light switches, where `1` means "on" and `0` means "off". Your goal is to find the **longest gap** between any two consecutive "on" switches.

    The key insight is that we only care about the positions of the `1` bits. As we scan through the binary representation, we need to track where the **previous** `1` was located. Each time we encounter a new `1`, we calculate the distance from the previous one and keep the maximum.

    Think of it like this: you're walking along a number line, and every time you see a `1`, you measure how far you've walked since the last `1`. The answer is the longest stretch you measured.

    We can extract bits from `n` one at a time using bitwise operations: `n & 1` gives the rightmost bit, and `n >> 1` shifts everything right (effectively dividing by 2).

  approach: |
    We solve this using a **Single Pass with Bit Extraction**:

    **Step 1: Initialise tracking variables**

    - `last_one`: Set to `-1` to indicate we haven't found a `1` yet
    - `max_gap`: Set to `0` since we return `0` if there are fewer than two `1`s
    - `position`: Set to `0` to track the current bit position as we iterate

    &nbsp;

    **Step 2: Extract bits from right to left**

    - Use `n & 1` to get the rightmost bit
    - If the bit is `1`:
      - If `last_one != -1`, calculate the gap: `position - last_one`
      - Update `max_gap` if this gap is larger
      - Update `last_one` to the current position
    - Shift `n` right by 1 (`n >>= 1`) to move to the next bit
    - Increment `position`
    - Continue until `n` becomes `0`

    &nbsp;

    **Step 3: Return the result**

    - Return `max_gap` after processing all bits

    &nbsp;

    This approach processes each bit exactly once, giving us optimal O(log n) time complexity.

  common_pitfalls:
    - title: Converting to String Unnecessarily
      description: |
        A common first approach is to convert the number to a binary string with `bin(n)` and then iterate through the characters.

        While this works, it uses **O(log n) extra space** for the string and involves string manipulation overhead. The bitwise approach is more efficient and teaches fundamental bit manipulation skills.
      wrong_approach: "bin(n) and string iteration"
      correct_approach: "Bitwise extraction with n & 1 and n >> 1"

    - title: Not Handling Single 1-Bit Case
      description: |
        Numbers like `8` (binary `1000`) or powers of 2 have only one `1` bit. Your algorithm must return `0` in these cases since there are no "adjacent" pairs.

        Initialising `last_one = -1` and only computing gaps when `last_one != -1` handles this naturally.
      wrong_approach: "Assuming there are always at least two 1-bits"
      correct_approach: "Track whether we've seen a previous 1 before computing gaps"

    - title: Confusing Bit Position with Bit Value
      description: |
        The problem asks for the **distance** between positions, not the number of zeros between them.

        For `n = 5` (binary `101`), the `1`s are at positions 0 and 2, so the gap is `2 - 0 = 2`, not `1` (the count of zeros between them).

        However, since consecutive bit positions differ by 1, the distance equals "zeros between + 1".
      wrong_approach: "Counting zeros between 1s"
      correct_approach: "Tracking positions and computing differences"

  key_takeaways:
    - "**Bit extraction pattern**: Use `n & 1` to get the rightmost bit and `n >>= 1` to shift right — this is fundamental for many bit manipulation problems"
    - "**Position tracking**: When dealing with bit positions, maintain a counter that increments as you process each bit"
    - "**Gap detection**: This pattern of tracking the 'last seen' position applies to many problems involving distances or intervals in sequences"
    - "**Space efficiency**: Bitwise operations avoid the memory overhead of string conversion"

  time_complexity: "O(log n). We process each bit of `n` exactly once, and a number `n` has `log2(n)` bits."
  space_complexity: "O(1). We only use a fixed number of variables (`last_one`, `max_gap`, `position`) regardless of input size."

solutions:
  - approach_name: Bitwise Extraction
    is_optimal: true
    code: |
      def binary_gap(n: int) -> int:
          # Track the position of the last 1 we saw (-1 means none yet)
          last_one = -1
          # Track the maximum gap found
          max_gap = 0
          # Current bit position (starting from rightmost = 0)
          position = 0

          while n > 0:
              # Check if the rightmost bit is 1
              if n & 1:
                  # If we've seen a 1 before, calculate the gap
                  if last_one != -1:
                      gap = position - last_one
                      max_gap = max(max_gap, gap)
                  # Update the position of the last 1
                  last_one = position

              # Move to the next bit (shift right)
              n >>= 1
              position += 1

          return max_gap
    explanation: |
      **Time Complexity:** O(log n) — We process each of the log2(n) bits exactly once.

      **Space Complexity:** O(1) — Only three integer variables used.

      We iterate through the bits from right to left using bitwise AND and right shift. Each time we find a `1`, we check if there was a previous `1` and calculate the gap. This approach is memory-efficient and demonstrates fundamental bit manipulation techniques.

  - approach_name: String Conversion
    is_optimal: false
    code: |
      def binary_gap(n: int) -> int:
          # Convert to binary string (e.g., '0b10110' -> '10110')
          binary = bin(n)[2:]
          max_gap = 0
          last_one = -1

          for i, bit in enumerate(binary):
              if bit == '1':
                  if last_one != -1:
                      gap = i - last_one
                      max_gap = max(max_gap, gap)
                  last_one = i

          return max_gap
    explanation: |
      **Time Complexity:** O(log n) — Converting to string and iterating both take O(log n).

      **Space Complexity:** O(log n) — The binary string requires O(log n) space.

      This approach converts the integer to its binary string representation and then iterates through the characters. While correct and readable, it uses extra space for the string. The bitwise approach is preferred for interviews to demonstrate low-level manipulation skills.
