868. Binary Gap
Problem Description
Given a positive integer n
, you need to find the longest distance between any two adjacent 1
s in its binary representation. If there are no two adjacent 1
s in the binary representation, return 0
.
Two 1
s are considered adjacent if they appear consecutively in the binary representation with only 0
s (or no 0
s) between them. The distance between two 1
s is calculated as the absolute difference between their bit positions.
For example:
- In the binary string
"1001"
, there are two1
s at positions 0 and 3 (counting from the right, starting at 0) - These two
1
s are adjacent because there are no other1
s between them - The distance between them is
3 - 0 = 3
The task is to examine all pairs of adjacent 1
s in the binary representation and return the maximum distance found. If the binary representation has fewer than two 1
s, there are no adjacent pairs, so the answer would be 0
.
Intuition
To find the longest distance between adjacent 1
s, we need to track where each 1
appears in the binary representation. The key insight is that we don't need to store all positions of 1
s - we only need to remember the position of the previous 1
to calculate distances.
Think of it like walking along the binary digits from right to left. Every time we encounter a 1
, we can calculate how far we've walked since the last 1
we saw. This distance is simply the difference between the current position and the previous position where we found a 1
.
We can process the number bit by bit using bit manipulation. By checking the least significant bit with n & 1
, we can determine if the current position has a 1
. After checking each bit, we shift the number right with n >>= 1
to examine the next bit.
The algorithm maintains:
pre
: the position of the previous1
we encountered (initialized to infinity to handle the first1
gracefully)cur
: our current position in the binary representationans
: the maximum distance found so far
Each time we find a 1
, we calculate cur - pre
to get the distance from the previous 1
, update our answer if this distance is larger, and then update pre
to the current position. This way, we're always comparing adjacent 1
s and keeping track of the maximum gap between them.
Solution Approach
The solution uses bit manipulation to efficiently traverse the binary representation of n
from right to left (least significant bit to most significant bit).
Variables Used:
ans
: Stores the maximum distance found between adjacent1
spre
: Position of the previous1
bit (initialized to infinity)cur
: Current bit position being examined (starts at 0)
Algorithm Steps:
-
Initialize variables: Set
ans = 0
,pre = inf
, andcur = 0
. Thepre = inf
initialization ensures that when we find the first1
, the distance calculationcur - pre
will be negative, which won't affect our answer since we're looking for the maximum. -
Traverse bits: Use a while loop that continues as long as
n > 0
:- Check if the current bit is
1
usingn & 1
- If it's a
1
:- Calculate the distance from the previous
1
:cur - pre
- Update the maximum distance:
ans = max(ans, cur - pre)
- Update
pre
to the current position:pre = cur
- Calculate the distance from the previous
- Increment the position counter:
cur += 1
- Shift
n
right by one bit:n >>= 1
- Check if the current bit is
-
Return result: After processing all bits, return
ans
Why this works:
- By checking
n & 1
, we examine the least significant bit - Right-shifting with
n >>= 1
moves to the next bit - We only update
pre
when we find a1
, ensuring we're always measuring distances between consecutive1
s - The
max()
function ensures we keep track of the longest distance encountered
Time Complexity: O(log n)
where n
is the input number, as we process each bit once.
Space Complexity: O(1)
as we only use a constant amount of extra space.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with n = 22
, which has binary representation 10110
.
Initial State:
ans = 0
(maximum distance found)pre = inf
(position of previous 1)cur = 0
(current position)n = 22
(binary:10110
)
Step-by-step execution:
Iteration 1: Binary: 10110
, checking rightmost bit
n & 1 = 0
(rightmost bit is 0)- No action since bit is 0
cur = 1
,n = 11
(aftern >>= 1
, binary:1011
)
Iteration 2: Binary: 1011
, checking rightmost bit
n & 1 = 1
(rightmost bit is 1)- Distance =
cur - pre = 1 - inf
(negative, won't update ans) ans = max(0, 1-inf) = 0
pre = 1
(update previous 1's position)cur = 2
,n = 5
(after shift, binary:101
)
Iteration 3: Binary: 101
, checking rightmost bit
n & 1 = 1
(rightmost bit is 1)- Distance =
cur - pre = 2 - 1 = 1
ans = max(0, 1) = 1
pre = 2
(update previous 1's position)cur = 3
,n = 2
(after shift, binary:10
)
Iteration 4: Binary: 10
, checking rightmost bit
n & 1 = 0
(rightmost bit is 0)- No action since bit is 0
cur = 4
,n = 1
(after shift, binary:1
)
Iteration 5: Binary: 1
, checking rightmost bit
n & 1 = 1
(rightmost bit is 1)- Distance =
cur - pre = 4 - 2 = 2
ans = max(1, 2) = 2
pre = 4
(update previous 1's position)cur = 5
,n = 0
(after shift)
Loop ends as n = 0
Result: The maximum distance between adjacent 1s is 2
, which corresponds to the gap between the 1s at positions 2 and 4 in the binary representation 10110
.
Solution Implementation
1class Solution:
2 def binaryGap(self, n: int) -> int:
3 """
4 Find the longest distance between two consecutive 1's in the binary representation of n.
5
6 Args:
7 n: A positive integer
8
9 Returns:
10 The maximum distance between two consecutive 1's in binary representation
11 """
12 # Initialize the maximum distance
13 max_distance = 0
14
15 # Track the position of the previous 1 bit (initialize to infinity)
16 previous_one_position = float('inf')
17
18 # Track the current bit position (0-indexed from right)
19 current_position = 0
20
21 # Process each bit of n from right to left
22 while n > 0:
23 # Check if the current bit is 1
24 if n & 1:
25 # Calculate distance from previous 1 and update maximum
26 max_distance = max(max_distance, current_position - previous_one_position)
27 # Update the position of the most recent 1
28 previous_one_position = current_position
29
30 # Move to the next bit position
31 current_position += 1
32 # Right shift n by 1 to process the next bit
33 n >>= 1
34
35 return max_distance
36
1class Solution {
2 public int binaryGap(int n) {
3 int maxGap = 0;
4
5 // Initialize previousPosition to a large value to handle edge case
6 // where there's only one '1' bit (result should be 0)
7 int previousPosition = 100;
8 int currentPosition = 0;
9
10 // Process each bit of n from right to left
11 while (n != 0) {
12 // Check if the current bit is 1
13 if (n % 2 == 1) {
14 // Update maximum gap between consecutive 1s
15 maxGap = Math.max(maxGap, currentPosition - previousPosition);
16 // Update previous 1's position for next comparison
17 previousPosition = currentPosition;
18 }
19
20 // Move to the next bit position
21 currentPosition++;
22 // Right shift n by 1 to process the next bit
23 n >>= 1;
24 }
25
26 return maxGap;
27 }
28}
29
1class Solution {
2public:
3 int binaryGap(int n) {
4 int maxDistance = 0;
5
6 // Initialize previous position to a large value (100) to handle edge case
7 // where there's only one '1' bit (resulting in maxDistance = 0)
8 int previousOnePosition = 100;
9 int currentPosition = 0;
10
11 // Iterate through each bit of n from right to left
12 while (n != 0) {
13 // Check if the current bit is 1
14 if (n & 1) {
15 // Calculate distance between current '1' and previous '1'
16 maxDistance = max(maxDistance, currentPosition - previousOnePosition);
17
18 // Update previous '1' position to current position
19 previousOnePosition = currentPosition;
20 }
21
22 // Move to the next bit position
23 ++currentPosition;
24
25 // Right shift n by 1 to check the next bit
26 n >>= 1;
27 }
28
29 return maxDistance;
30 }
31};
32
1/**
2 * Finds the longest distance between any two adjacent 1's in the binary representation of n.
3 * If there are no two adjacent 1's, returns 0.
4 *
5 * @param n - A positive integer
6 * @returns The maximum binary gap
7 */
8function binaryGap(n: number): number {
9 let maxGap: number = 0;
10 let previousOnePosition: number = 100; // Initialize to a large value to handle edge case
11 let currentPosition: number = 0;
12
13 // Process each bit of n from right to left
14 while (n > 0) {
15 // Check if the current bit is 1
16 if ((n & 1) === 1) {
17 // Calculate gap between current 1 and previous 1
18 maxGap = Math.max(maxGap, currentPosition - previousOnePosition);
19 // Update previous 1's position to current position
20 previousOnePosition = currentPosition;
21 }
22
23 // Move to the next bit position
24 currentPosition++;
25 // Right shift n by 1 to process the next bit
26 n >>= 1;
27 }
28
29 return maxGap;
30}
31
Time and Space Complexity
The time complexity is O(log n)
, where n
is the given integer. This is because the while loop continues as long as n > 0
, and in each iteration, we right shift n
by 1 bit (equivalent to dividing by 2). Since we're essentially counting the number of bits in the binary representation of n
, and a number n
has approximately log₂(n)
bits, the loop runs O(log n)
times.
The space complexity is O(1)
. The algorithm only uses a constant amount of extra space for the variables ans
, pre
, and cur
, regardless of the input size. No additional data structures that grow with input size are used.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Misunderstanding "Adjacent" 1s
The Problem: Many developers initially interpret "adjacent 1s" as 1s that are directly next to each other (like 11
in binary), leading them to look for patterns where the distance would always be 1.
Why It Happens: The term "adjacent" in everyday language often means "next to each other," but in this problem, it means consecutive 1s in the sequence with any number of 0s between them.
Example of Incorrect Understanding:
# WRONG: Looking for directly neighboring 1s
def binaryGap_wrong(n: int):
binary = bin(n)[2:]
max_gap = 0
for i in range(len(binary) - 1):
if binary[i] == '1' and binary[i+1] == '1':
max_gap = 1 # This would always be 1!
return max_gap
Solution: Remember that "adjacent" here means consecutive occurrences of 1s in the bit sequence, not physically neighboring bits. The correct approach tracks positions of all 1s and measures distances between consecutive pairs.
Pitfall 2: Incorrect Initialization of Previous Position
The Problem: Initializing previous_one_position
to 0 instead of infinity can cause incorrect results when the first 1 appears at position 0.
Why It Happens:
# WRONG initialization previous_one_position = 0 # Problematic! current_position = 0 # When first 1 is found at position 0: # distance = 0 - 0 = 0 (incorrect, should not count)
Example Causing Issues:
- Input:
n = 8
(binary:1000
) - With
previous_one_position = 0
, when we find the 1 at position 3, we'd calculate distance as 3-0=3, which is wrong since there's only one 1.
Solution: Initialize to float('inf')
so the first distance calculation yields a negative number (which won't affect the maximum) and ensures we only start counting distances after finding at least two 1s.
Pitfall 3: Using String Conversion Instead of Bit Manipulation
The Problem: Converting to binary string and then processing can be less efficient and more error-prone.
Why It Happens:
# Less efficient approach
def binaryGap_string(n: int):
binary = bin(n)[2:] # Creates string allocation
positions = []
for i, bit in enumerate(binary):
if bit == '1':
positions.append(len(binary) - 1 - i) # Easy to mess up indexing!
# ... rest of logic
Issues with String Approach:
- Extra memory allocation for string
- Confusion with indexing (left-to-right vs right-to-left)
- Need to handle string slicing (
[2:]
to remove '0b' prefix)
Solution: Stick with bit manipulation using n & 1
and n >>= 1
for cleaner, more efficient code that directly works with the binary representation without conversion overhead.
What's the output of running the following function using the following tree as input?
1def serialize(root):
2 res = []
3 def dfs(root):
4 if not root:
5 res.append('x')
6 return
7 res.append(root.val)
8 dfs(root.left)
9 dfs(root.right)
10 dfs(root)
11 return ' '.join(res)
12
1import java.util.StringJoiner;
2
3public static String serialize(Node root) {
4 StringJoiner res = new StringJoiner(" ");
5 serializeDFS(root, res);
6 return res.toString();
7}
8
9private static void serializeDFS(Node root, StringJoiner result) {
10 if (root == null) {
11 result.add("x");
12 return;
13 }
14 result.add(Integer.toString(root.val));
15 serializeDFS(root.left, result);
16 serializeDFS(root.right, result);
17}
18
1function serialize(root) {
2 let res = [];
3 serialize_dfs(root, res);
4 return res.join(" ");
5}
6
7function serialize_dfs(root, res) {
8 if (!root) {
9 res.push("x");
10 return;
11 }
12 res.push(root.val);
13 serialize_dfs(root.left, res);
14 serialize_dfs(root.right, res);
15}
16
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!