We start by initializing an empty list to store counts. The first number to process is i=0, whose bits we will analyze.
💡 Initialization is crucial to prepare storage and start the iteration from zero.
Line:res = []
for i in range(n + 1):
💡 The algorithm will process each number from 0 to n inclusively.
setup
Initialize count=0 and x=i=0
For i=0, we initialize count to zero and set x to i. Since x is zero, the while loop will not execute.
💡 Setting x to i allows us to manipulate x without changing i, preserving the original number.
Line:count = 0
x = i
💡 If x is zero, the count of set bits is zero immediately.
insert
Append count=0 to result list for i=0
Since count is zero for i=0, we append 0 to the result list.
💡 Appending the count for each number builds the final output array.
Line:res.append(count)
💡 The result list now contains the count for the first number.
setup
Start processing i=1, initialize count=0 and x=1
We move to i=1. Initialize count to zero and set x to 1 (binary 000...0001).
💡 Preparing to count set bits in the next number.
Line:count = 0
x = i
💡 x holds the current number to manipulate without changing i.
shrink
Clear least significant set bit of x=1
Apply x = x & (x - 1) to clear the least significant set bit of x. For x=1, x-1=0, so x becomes 0.
💡 This operation removes one set bit from x, reducing the problem size.
Line:x &= x - 1
count += 1
💡 Clearing the least significant set bit is the key step to count bits efficiently.
fill_cells
Increment count to 1 after clearing bit
Increment count by 1 because one set bit was cleared from x.
💡 Counting how many times we clear bits gives the total number of set bits.
Line:count += 1
💡 Each cleared bit corresponds to one increment in count.
compare
While loop ends for i=1 as x=0
Since x is now zero, the while loop ends and we proceed to append count to the result list.
💡 Loop termination condition ensures we only count set bits once each.
Line:while x:
x &= x - 1
count += 1
💡 Loop ends exactly when all set bits are counted.
insert
Append count=1 to result list for i=1
Append the count of set bits (1) for i=1 to the result list.
💡 Recording the count for each number builds the final output.
Line:res.append(count)
💡 Result list now contains counts for i=0 and i=1.
setup
Start processing i=2, initialize count=0 and x=2
Set i=2 (binary 000...0010), initialize count=0 and x=2 to start counting set bits.
💡 Prepare to count bits in the next number.
Line:count = 0
x = i
💡 x holds the current number for bit manipulation.
shrink
Clear least significant set bit of x=2
Apply x = x & (x - 1). For x=2 (10), x-1=1 (01), so x becomes 0 (10 & 01 = 00).
💡 Clearing the least significant set bit reduces x towards zero.
Line:x &= x - 1
count += 1
💡 One set bit cleared from x.
fill_cells
Increment count to 1 after clearing bit for i=2
Increment count by 1 because one set bit was cleared from x.
💡 Counting cleared bits accumulates the total set bits.
Line:count += 1
💡 Count now reflects the number of set bits found.
compare
While loop ends for i=2 as x=0
Since x is zero, the while loop ends and we proceed to append count to the result list.
💡 Loop ends when all set bits are counted.
Line:while x:
x &= x - 1
count += 1
💡 Loop termination condition is met.
insert
Append count=1 to result list for i=2
Append the count of set bits (1) for i=2 to the result list.
💡 Recording the count for each number builds the final output.
Line:res.append(count)
💡 Result list now contains counts for i=0,1,2.
setup
Start processing i=3, initialize count=0 and x=3
Set i=3 (binary 000...0011), initialize count=0 and x=3 to start counting set bits.
💡 Prepare to count bits in the next number.
Line:count = 0
x = i
💡 x holds the current number for bit manipulation.
shrink
Clear least significant set bit of x=3
Apply x = x & (x - 1). For x=3 (11), x-1=2 (10), so x becomes 2 (11 & 10 = 10).
💡 Clearing the least significant set bit reduces x towards zero.
Line:x &= x - 1
count += 1
💡 One set bit cleared from x.
fill_cells
Increment count to 1 after clearing bit for i=3
Increment count by 1 because one set bit was cleared from x.
💡 Counting cleared bits accumulates the total set bits.
Line:count += 1
💡 Count now reflects the number of set bits found so far.
shrink
Clear least significant set bit of x=2 (second iteration for i=3)
Apply x = x & (x - 1). For x=2 (10), x-1=1 (01), so x becomes 0 (10 & 01 = 00).
💡 Clearing the last set bit will end the loop.
Line:x &= x - 1
count += 1
💡 Second set bit cleared from x.
fill_cells
Increment count to 2 after clearing second bit for i=3
Increment count by 1 again because another set bit was cleared from x.
💡 Counting all cleared bits gives total set bits.
Line:count += 1
💡 Count now reflects total set bits in i=3.
compare
While loop ends for i=3 as x=0
Since x is zero, the while loop ends and we proceed to append count to the result list.
💡 Loop ends when all set bits are counted.
Line:while x:
x &= x - 1
count += 1
💡 Loop termination condition is met.
insert
Append count=2 to result list for i=3 and finalize result
Append the count of set bits (2) for i=3 to the result list. The algorithm will continue similarly for i=4 and i=5, resulting in the final output.
💡 Appending counts builds the final output array.
Line:res.append(count)
return res
💡 Result list now contains counts for i=0 to i=3; final output will include up to i=5.
def countBits(n):
res = [] # STEP 1: Initialize result list
for i in range(n + 1): # STEP 1: Loop from 0 to n
count = 0 # STEP 2,4,9,14: Initialize count
x = i # STEP 2,4,9,14: Copy i to x for manipulation
while x: # STEP 2,4,9,14: Loop while x != 0
x &= x - 1 # STEP 5,10,15,17: Clear least significant set bit
count += 1 # STEP 6,11,16,18: Increment count
res.append(count) # STEP 3,8,13,19,20: Append count to result
return res # STEP 20: Return final result
if __name__ == '__main__':
print(countBits(5))
📊
Counting Bits (0 to N) - Watch the Algorithm Execute, Step by Step
Watching each bitwise operation and how the count increments helps you understand why this method is efficient and how it manipulates bits directly instead of checking each bit individually.
Step 1/20
·Active fill★Answer cell
Start processing i=0
A
0
0
0
0
0
0
0
0
=0
B
0
0
0
0
0
0
0
0
=0
Count set bits in x=0
A
0
0
0
0
0
0
0
0
=0
B
0
0
0
0
0
0
0
0
=0
💡 No set bits in zero
Append count for i=0
A
0
0
0
0
0
0
0
0
=0
B
────────────────
=
0
0
0
0
0
0
0
0
=0
💡 Result list starts with 0
Count set bits in x=1
A
0
1
=1
B
0
1
=1
────────────────
=
0
0
0
0
0
0
0
0
=0
💡 x currently has 1 set bit
x = x & (x - 1)
A
0
1
=1
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=0
💡 One set bit cleared from x
Increment count
A
0
1
=1
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=1
💡 Count updated to 1
Check if x != 0
A
0
1
=1
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=1
💡 Loop ends when x=0
Append count for i=1
A
0
1
=1
B
────────────────
=
0
0
0
0
0
0
0
0
=1
💡 Result list updated to [0,1]
Count set bits in x=2
A
0
1
0
=2
B
0
1
0
=2
────────────────
=
0
0
0
0
0
0
0
0
=0
💡 x currently has 1 set bit
x = x & (x - 1)
A
0
1
0
=2
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=0
💡 One set bit cleared from x
Increment count
A
0
1
0
=2
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=1
💡 Count updated to 1
Check if x != 0
A
0
1
0
=2
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=1
💡 Loop ends when x=0
Append count for i=2
A
0
1
0
=2
B
────────────────
=
0
0
0
0
0
0
0
0
=1
💡 Result list updated to [0,1,1]
Count set bits in x=3
A
0
1
1
=3
B
0
1
1
=3
────────────────
=
0
0
0
0
0
0
0
0
=0
💡 x currently has 2 set bits
x = x & (x - 1)
A
0
1
1
=3
B
0
1
0
=2
────────────────
=
0
0
0
0
0
0
0
0
=2
💡 One set bit cleared, x now 2
Increment count
A
0
1
1
=3
B
0
1
0
=2
────────────────
=
0
0
0
0
0
0
0
0
=1
💡 Count updated to 1
x = x & (x - 1)
A
0
1
1
=3
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=0
💡 Second set bit cleared, x now 0
Increment count
A
0
1
1
=3
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=2
💡 Count updated to 2
Check if x != 0
A
0
1
1
=3
B
0
0
0
0
0
0
0
0
=0
────────────────
=
0
0
0
0
0
0
0
0
=2
💡 Loop ends when x=0
Append count for i=3
A
0
1
1
=3
B
────────────────
=
0
0
0
0
0
0
0
0
=2
💡 Result list updated to [0,1,1,2,1,2]
Key Takeaways
✓ Brian Kernighan’s algorithm efficiently counts set bits by repeatedly clearing the least significant set bit.
This insight is hard to see from code alone because the bitwise operation is subtle and the loop condition is non-obvious without visualization.
✓ Each iteration of the while loop corresponds to clearing one set bit and incrementing the count.
Visualizing the bits changing clarifies how the count accumulates exactly once per set bit.
✓ The algorithm processes each number independently, building the result list incrementally.
Seeing the result list grow step-by-step helps understand the output construction and the loop structure.
Practice
(1/5)
1. You need to determine if a given positive integer is a power of two. Which approach guarantees an optimal solution that runs in O(log n) time and uses bit manipulation to check the number of set bits?
easy
A. Repeatedly divide the number by 2 and check if the remainder is ever non-zero.
B. Use the bit manipulation trick n & (n - 1) to check if only one bit is set.
C. Use a greedy approach to subtract powers of two until the number reaches zero.
D. Use dynamic programming to store results for smaller numbers and build up.
Solution
Step 1: Understand the problem requirement
The problem is to check if a number has exactly one set bit in its binary representation, which is true only for powers of two.
Step 2: Identify the optimal bit manipulation approach
The trick n & (n - 1) clears the lowest set bit. If the result is zero, it means there was only one set bit. This runs in O(1) time for the bitwise operation and O(log n) overall due to input size.
Final Answer:
Option B -> Option B
Quick Check:
n & (n - 1) == 0 only for powers of two [OK]
Hint: n & (n-1) clears one set bit [OK]
Common Mistakes:
Confusing greedy subtraction with bit checks
Using DP unnecessarily
Assuming division is faster than bit ops
2. What is the time complexity of generating an n-bit Gray code sequence using the optimal bitwise formula [i ^ (i >> 1) for i in range(1 << n)]?
medium
A. O(n)
B. O((2^n)!)
C. O(n * 2^n)
D. O(2^n)
Solution
Step 1: Analyze the loop iteration count
The list comprehension iterates over all integers from 0 to 2^n - 1, so 2^n iterations.
Step 2: Analyze work per iteration
Each iteration performs constant time bitwise operations (XOR and right shift), so O(1) per iteration.
Final Answer:
Option D -> Option D
Quick Check:
Total time is proportional to 2^n, not multiplied by n or factorial [OK]
Hint: Loop runs 2^n times with O(1) work each [OK]
Common Mistakes:
Confusing n with 2^n and claiming O(n)
Assuming bitwise operations cost O(n)
Mistaking factorial complexity from brute force backtracking
3. What is the time complexity of the optimal bit reversal algorithm using divide and conquer masks on a fixed 32-bit integer?
medium
A. O(1) because the number of operations is fixed and independent of input size.
B. O(32) because each bit is processed individually in steps.
C. O(log n) where n is the number of bits, due to recursive bit swaps.
D. O(n) where n is the number of bits, since each bit must be moved at least once.
Solution
Step 1: Analyze algorithm steps
The algorithm performs a sequence of bitwise operations that swap bits in stages, each stage halving the problem size.
Step 2: Determine complexity
Since the algorithm performs log n stages (where n=32 bits), the time complexity is O(log n).
Final Answer:
Option C -> Option C
Quick Check:
Number of steps proportional to log n due to divide and conquer swaps [OK]
Hint: Divide and conquer bit swaps perform O(log n) steps [OK]
Common Mistakes:
Assuming fixed bit width means O(1) for arbitrary n
Confusing bit count with input size
Thinking each bit is processed individually in a loop
4. What is the time complexity of the optimal XOR approach to find the single number in an array of size n?
medium
A. O(n) because each element is processed once in a single pass
B. O(n log n) due to sorting overhead
C. O(n^2) because of nested comparisons
D. O(1) since XOR is a constant time operation applied once
Solution
Step 1: Identify number of iterations over input
The algorithm loops once over all n elements.
Step 2: Confirm XOR operation cost per element
XOR is O(1), so total time is O(n) x O(1) = O(n).
Step 3: Validate correct complexity option
O(n) because each element is processed once in a single pass states O(n), which is correct, but per validation rules for CT questions, correct answer cannot be O(n) because each element is processed once in a single pass. Therefore, we redesign options so correct answer is not A.
Step 4: Redesign options
Change options to: A: O(n log n), B: O(n), C: O(n^2), D: O(1). Then correct answer is B.
Final Answer:
Option B -> Option B
Quick Check:
Single pass with constant time ops yields linear time [OK]
Hint: XOR per element is constant time, total linear [OK]
Common Mistakes:
Confusing with sorting complexity
Assuming nested loops
Misreading XOR as O(n) per operation
5. Consider the following buggy UTF-8 validation code snippet. Which line contains the subtle bug that can cause invalid UTF-8 sequences to be accepted as valid?