LeetCode 693 - Binary Number with Alternating Bits
The problem asks us to determine whether the binary representation of a given positive integer n has alternating bits. In other words, for the binary digits of n, no two consecutive bits should be the same.
Difficulty: 🟢 Easy
Topics: Bit Manipulation
Solution
Problem Understanding
The problem asks us to determine whether the binary representation of a given positive integer n has alternating bits. In other words, for the binary digits of n, no two consecutive bits should be the same. For example, 101 is alternating, while 111 is not because it contains consecutive ones.
The input n is guaranteed to be a positive integer within the range 1 <= n <= 2^31 - 1, which corresponds to a 32-bit signed integer range. This constraint ensures that n can be safely handled using standard integer types in Python or Go without overflow.
The expected output is a boolean: true if n has alternating bits and false otherwise.
Important edge cases include the smallest possible input n = 1, which trivially has alternating bits, numbers with all ones (e.g., 7), and numbers with alternating bits ending in 0 or 1.
Approaches
The brute-force approach is straightforward. We can repeatedly extract the least significant bit of the number and compare it with the previous bit. If any two consecutive bits are the same, we return false. Otherwise, we continue until all bits are checked. This approach is correct because it directly verifies the definition of alternating bits, but it may perform up to 32 comparisons for a 32-bit integer, which is acceptable but not optimal.
A more optimal solution uses bit manipulation. Consider that for a number with alternating bits, shifting the number right by one bit and XORing it with the original number should produce a binary number with all bits set to 1. This is because XOR returns 1 for differing bits and 0 for equal bits. Once we get this XOR result, we can check if it is of the form 2^k - 1 by verifying that x & (x + 1) == 0. This property comes from the observation that numbers like 1, 11, 111, etc., in binary satisfy this identity.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(log n) | O(1) | Iteratively compare each bit with the previous bit |
| Optimal | O(log n) | O(1) | Use bit manipulation and XOR to check pattern in a single step |
Algorithm Walkthrough
- Start with the input number
n. - Compute
shifted = n >> 1. This moves all bits ofnone position to the right. - Compute
xor_result = n ^ shifted. This XOR operation will produce a number where each bit is1if the original bits were different, which is exactly what alternating bits produce. - To check whether
xor_resultis a sequence of all1s, use the expressionxor_result & (xor_result + 1). If the result is0, thenxor_resultis of the form2^k - 1, meaningnhas alternating bits. - Return
trueif the check passes, otherwisefalse.
Why it works: The algorithm relies on the property that XOR of consecutive bits in an alternating sequence produces all ones, and all ones in binary satisfy the identity x & (x + 1) == 0. This invariant guarantees correctness for all valid input numbers.
Python Solution
class Solution:
def hasAlternatingBits(self, n: int) -> bool:
shifted = n >> 1
xor_result = n ^ shifted
return (xor_result & (xor_result + 1)) == 0
In this implementation, the first step shifts n by one to align consecutive bits for comparison. The XOR operation detects where bits differ, and the final check ensures all bits in xor_result are set, which indicates alternating bits. This method avoids iterating over each bit individually.
Go Solution
func hasAlternatingBits(n int) bool {
shifted := n >> 1
xorResult := n ^ shifted
return (xorResult & (xorResult + 1)) == 0
}
The Go implementation mirrors Python’s approach. Bitwise operations are used directly on integers. There are no concerns with integer overflow within the 32-bit range of the problem constraints, and Go handles bitwise operations on int types efficiently.
Worked Examples
Example 1: n = 5 (binary 101)
| Step | Value |
|---|---|
| n | 101 |
| shifted | 010 |
| xor_result | 111 |
| xor_result & (xor_result + 1) | 111 & 1000 = 0 |
| Return | true |
Example 2: n = 7 (binary 111)
| Step | Value |
|---|---|
| n | 111 |
| shifted | 011 |
| xor_result | 100 |
| xor_result & (xor_result + 1) | 100 & 101 = 100 != 0 |
| Return | false |
Example 3: n = 11 (binary 1011)
| Step | Value |
|---|---|
| n | 1011 |
| shifted | 0101 |
| xor_result | 1110 |
| xor_result & (xor_result + 1) | 1110 & 1111 = 1110 != 0 |
| Return | false |
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(log n) | Each bit is processed once in the XOR and shift operations; the number of bits is proportional to log n |
| Space | O(1) | Only a constant number of integer variables are used |
The complexity is efficient for 32-bit integers, and the approach is scalable to larger numbers as well.
Test Cases
# test cases
assert Solution().hasAlternatingBits(5) == True # 101
assert Solution().hasAlternatingBits(7) == False # 111
assert Solution().hasAlternatingBits(11) == False # 1011
assert Solution().hasAlternatingBits(1) == True # single bit
assert Solution().hasAlternatingBits(10) == True # 1010
assert Solution().hasAlternatingBits(0b1010101) == True # 85, longer alternating
assert Solution().hasAlternatingBits(0b1111111) == False # all ones
assert Solution().hasAlternatingBits(0b100000) == True # 32, single one at high bit
| Test | Why |
|---|---|
| 5 | Standard alternating pattern |
| 7 | All bits the same |
| 11 | Non-alternating with mixture of ones and zeros |
| 1 | Single bit edge case |
| 10 | Alternating ending with zero |
| 85 | Longer alternating pattern |
| 127 | All ones, edge case |
| 32 | Single one at high position, alternating trivially |
Edge Cases
One important edge case is n = 1. Since it has only one bit, it should return true. A naive implementation comparing consecutive bits might fail if it does not handle single-bit numbers properly. Our bitwise approach handles it naturally because the XOR of n with n >> 1 produces 1, and the final check (1 & 2) == 0 holds.
Another edge case is numbers with all ones in their binary representation, like n = 7 or n = 127. These numbers do not have alternating bits, and the XOR approach detects the pattern correctly, returning false because the XOR result is not all ones.
A third edge case is numbers where the alternating pattern ends with 0, such as n = 10 (binary 1010). Some iterative solutions might assume alternating sequences must start or end with 1. Our solution does not have this bias, since the XOR and bit check correctly handle both cases.