title: Binary Number with Alternating Bits
slug: binary-number-with-alternating-bits
difficulty: easy
leetcode_id: 693
leetcode_url: https://leetcode.com/problems/binary-number-with-alternating-bits/
categories:
  - math
patterns:
  - slug: greedy
    is_optimal: true

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

test_cases:
  visible:
    - input: { n: 5 }
      expected: true
    - input: { n: 7 }
      expected: false
    - input: { n: 11 }
      expected: false
  hidden:
    - input: { n: 1 }
      expected: true
    - input: { n: 2 }
      expected: true
    - input: { n: 10 }
      expected: true
    - input: { n: 21 }
      expected: true
    - input: { n: 15 }
      expected: false
    - input: { n: 1431655765 }
      expected: true
    - input: { n: 4 }
      expected: false

description: |
  Given a positive integer `n`, check whether it has **alternating bits**: namely, if two adjacent bits will always have different values.

  Return `true` if the given integer has alternating bits, otherwise return `false`.

constraints: |
  - `1 <= n <= 2^31 - 1`

examples:
  - input: "n = 5"
    output: "true"
    explanation: "The binary representation of 5 is 101, where each adjacent pair of bits differs."
  - input: "n = 7"
    output: "false"
    explanation: "The binary representation of 7 is 111, where adjacent bits are the same."
  - input: "n = 11"
    output: "false"
    explanation: "The binary representation of 11 is 1011, where the two rightmost bits are both 1."

explanation:
  intuition: |
    Think of the binary representation of a number as a sequence of 0s and 1s. A number has "alternating bits" if the pattern looks like `...1010...` or `...0101...` — no two adjacent bits are the same.

    Imagine walking through the binary digits from right to left (least significant to most significant). At each step, you compare the current bit with the previous one. If they're ever the same, you know the bits don't alternate.

    The key insight is that we can extract the last bit of any number using `n & 1` (bitwise AND with 1), and then shift the number right by one position using `n >> 1` to move to the next bit. This lets us examine each bit in sequence without converting to a string.

    Another elegant approach uses a mathematical trick: if we XOR the number with itself shifted by one position (`n ^ (n >> 1)`), a number with alternating bits produces all 1s. For example, `5 = 101` shifted gives `010`, and `101 ^ 010 = 111`. If the result is all 1s, we can verify by checking if adding 1 creates a power of two.

  approach: |
    We solve this using **Bit-by-Bit Comparison**:

    **Step 1: Extract the last bit**

    - Use `prev_bit = n & 1` to get the rightmost bit
    - Shift `n` right by 1 to prepare for the next iteration

    &nbsp;

    **Step 2: Iterate through remaining bits**

    - While `n > 0`, extract the current last bit with `curr_bit = n & 1`
    - Compare `curr_bit` with `prev_bit`
    - If they're equal, return `false` immediately — adjacent bits are the same
    - Otherwise, update `prev_bit = curr_bit` and shift `n` right by 1

    &nbsp;

    **Step 3: Return the result**

    - If we complete the loop without finding equal adjacent bits, return `true`

    &nbsp;

    This approach examines each bit exactly once, making it efficient and straightforward.

  common_pitfalls:
    - title: Converting to String
      description: |
        A tempting first approach is to convert the number to a binary string using `bin(n)` and then check adjacent characters:

        ```python
        s = bin(n)[2:]  # Remove '0b' prefix
        for i in range(len(s) - 1):
            if s[i] == s[i+1]:
                return False
        ```

        While this works, it uses O(log n) extra space for the string and is less efficient than bit manipulation. String operations also have overhead compared to bitwise operations.
      wrong_approach: "Convert to binary string and compare characters"
      correct_approach: "Use bit manipulation to extract and compare bits directly"

    - title: Off-by-One in Bit Extraction
      description: |
        When using `n % 2` instead of `n & 1`, the logic is equivalent but ensure you're consistent. A common mistake is forgetting to shift the number after extracting a bit, leading to an infinite loop.

        Always pair bit extraction with `n >>= 1` (or `n //= 2`) to advance through the bits.
      wrong_approach: "Extract bit without shifting"
      correct_approach: "Always shift after extracting each bit"

    - title: Not Handling Single Bit Numbers
      description: |
        Numbers like `1` or `2` have only one bit set (binary `1` or `10`). These trivially have "alternating bits" since there's no pair of adjacent 1s.

        Make sure your loop handles these cases correctly — they should return `true`.

  key_takeaways:
    - "**Bit extraction pattern**: Use `n & 1` to get the last bit and `n >> 1` to shift right — this is fundamental for bit manipulation"
    - "**XOR trick**: `n ^ (n >> 1)` produces all 1s for alternating bit patterns — useful for one-liner solutions"
    - "**Avoid string conversion**: Direct bit manipulation is more space-efficient and often faster than string operations"
    - "**Powers of two check**: A number with all bits set to 1 plus 1 equals a power of two — `(x & (x + 1)) == 0` verifies this"

  time_complexity: "O(log n). We examine each bit of `n` exactly once, and there are `log n` bits in a number `n`."
  space_complexity: "O(1). We only use a constant number of variables regardless of input size."

solutions:
  - approach_name: Bit-by-Bit Comparison
    is_optimal: true
    code: |
      def has_alternating_bits(n: int) -> bool:
          # Extract the last bit to start comparison
          prev_bit = n & 1
          n >>= 1  # Move to the next bit

          while n > 0:
              # Extract current last bit
              curr_bit = n & 1

              # Adjacent bits must be different
              if curr_bit == prev_bit:
                  return False

              # Move to next bit
              prev_bit = curr_bit
              n >>= 1

          return True
    explanation: |
      **Time Complexity:** O(log n) — We iterate through each bit once.

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

      We extract bits from right to left using bitwise AND and right shift. By comparing each bit with the previous one, we can detect any adjacent pair of identical bits.

  - approach_name: XOR Trick
    is_optimal: true
    code: |
      def has_alternating_bits(n: int) -> bool:
          # XOR n with n shifted right by 1
          # For alternating bits, this produces all 1s
          xor_result = n ^ (n >> 1)

          # Check if xor_result is all 1s: (x & (x + 1)) == 0
          # All 1s like 111 plus 1 gives 1000, AND gives 0
          return (xor_result & (xor_result + 1)) == 0
    explanation: |
      **Time Complexity:** O(1) — Constant number of bitwise operations.

      **Space Complexity:** O(1) — Only one additional variable.

      This elegant approach exploits a property of alternating bits. When we XOR a number with its right-shifted version, alternating patterns like `101` become `111` (all 1s). We then verify the result is all 1s by checking if adding 1 and ANDing gives zero.

  - approach_name: String Conversion
    is_optimal: false
    code: |
      def has_alternating_bits(n: int) -> bool:
          # Convert to binary string (without '0b' prefix)
          binary = bin(n)[2:]

          # Check each adjacent pair of characters
          for i in range(len(binary) - 1):
              if binary[i] == binary[i + 1]:
                  return False

          return True
    explanation: |
      **Time Complexity:** O(log n) — Converting to string and iterating through it.

      **Space Complexity:** O(log n) — The binary string requires space proportional to the number of bits.

      While straightforward, this approach uses extra space for the string representation. Included here to show a more readable but less efficient alternative.
