Count Set Bits Brian Kernighan Algorithm in DSA Rust - Time & Space Complexity
We want to understand how fast the Brian Kernighan algorithm counts the number of 1s in a binary number.
How does the time it takes change as the number gets bigger?
Analyze the time complexity of the following code snippet.
fn count_set_bits(mut n: u32) -> u32 {
let mut count = 0;
while n != 0 {
n &= n - 1; // Remove the rightmost set bit
count += 1;
}
count
}
This code counts how many bits are set to 1 in the number by repeatedly removing the rightmost 1 bit.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop runs once for each set bit in the number.
- How many times: Equal to the number of 1 bits in the input number.
The number of loop runs depends on how many 1s are in the number, not its size in bits.
| Input Size (n) | Approx. Operations (loop runs) |
|---|---|
| 10 (binary 1010) | 2 |
| 100 (binary 1100100) | 3 |
| 1000 (binary 1111101000) | 6 |
Pattern observation: The loop count grows with the number of 1 bits, which can be much less than total bits.
Time Complexity: O(k)
This means the time grows with the number of set bits k in the number, not the total bits.
[X] Wrong: "The loop runs once for every bit in the number (always 32 or 64 times)."
[OK] Correct: The loop only runs as many times as there are 1 bits, which can be much fewer than total bits.
Understanding this algorithm shows you can optimize bit counting by focusing on set bits, a useful skill in many coding problems.
"What if we changed the input to always have half of its bits set? How would the time complexity change?"
Practice
Solution
Step 1: Understand the algorithm's main operation
The Brian Kernighan algorithm works by clearing the least significant set bit in each iteration.Step 2: Effect of clearing bits
Each time the least significant set bit is cleared, the count of set bits increases by one until the number becomes zero.Final Answer:
It repeatedly clears the least significant set bit until the number becomes zero -> Option AQuick Check:
Clearing bits one by one counts set bits [OK]
- Counting total bits instead of set bits
- Using string conversion instead of bit operations
- Shifting without checking bits
Solution
Step 1: Identify the Brian Kernighan algorithm code
fn count_set_bits(mut n: u32) -> u32 { let mut count = 0; while n != 0 { n &= n - 1; count += 1; } count } uses the loop with n &= n - 1 to clear the least significant set bit repeatedly.Step 2: Verify other options
fn count_set_bits(n: u32) -> u32 { n.count_ones() } uses built-in count_ones(), fn count_set_bits(mut n: u32) -> u32 { let mut count = 0; while n > 0 { count += n & 1; n >>= 1; } count } uses bit shifting, and fn count_set_bits(n: u32) -> u32 { n.trailing_zeros() } uses trailing_zeros(), which are not Brian Kernighan's method.Final Answer:
fn count_set_bits(mut n: u32) -> u32 { let mut count = 0; while n != 0 { n &= n - 1; count += 1; } count } -> Option DQuick Check:
n &= n - 1 loop is Brian Kernighan's method [OK]
- Using built-in functions instead of algorithm
- Shifting bits instead of clearing
- Using trailing_zeros which counts zeros, not ones
fn main() {
let mut n = 29u32; // binary 11101
let mut count = 0;
while n != 0 {
n &= n - 1;
count += 1;
}
println!("{}", count);
}Solution
Step 1: Convert 29 to binary and count set bits
29 in binary is 11101, which has four set bits (1s).Step 2: Apply Brian Kernighan algorithm steps
Each iteration clears one set bit until n becomes zero, so count increments 4 times.Final Answer:
4 -> Option BQuick Check:
Number of 1s in 11101 = 4 [OK]
- Counting total bits instead of set bits
- Miscounting binary digits
- Confusing zero bits with set bits
fn count_set_bits(mut n: u32) -> u32 {
let mut count = 0;
while n > 0 {
n = n - 1;
count += 1;
}
count
}Solution
Step 1: Analyze the loop operation on n
The code subtracts 1 from n each time, which does not clear the least significant set bit correctly.Step 2: Understand Brian Kernighan's method
The correct operation is n &= n - 1 to clear the least significant set bit, not n = n - 1.Final Answer:
It decrements n by 1 instead of clearing the least significant set bit -> Option CQuick Check:
Use n &= n - 1 to clear bits, not n = n - 1 [OK]
- Using subtraction instead of bitwise AND
- Wrong loop condition causing infinite loop
- Not incrementing count properly
[7, 8, 15, 23], which Rust code using Brian Kernighan's algorithm correctly returns a vector of their set bit counts?Solution
Step 1: Identify Brian Kernighan's algorithm in code
fn count_bits_list(nums: &[u32]) -> Vec<u32> { nums.iter().map(|&n| { let mut x = n; let mut c = 0; while x != 0 { x &= x - 1; c += 1; } c }).collect() } uses the loop with x &= x - 1 to count set bits for each number.Step 2: Check other options
Options B, C, and D use built-in functions not related to Brian Kernighan's algorithm.Step 3: Confirm output correctness
fn count_bits_list(nums: &[u32]) -> Vec<u32> { nums.iter().map(|&n| { let mut x = n; let mut c = 0; while x != 0 { x &= x - 1; c += 1; } c }).collect() } returns a vector with counts of set bits for each number in the list.Final Answer:
fn count_bits_list(nums: &[u32]) -> Vec<u32> { nums.iter().map(|&n| { let mut x = n; let mut c = 0; while x != 0 { x &= x - 1; c += 1; } c }).collect() } -> Option AQuick Check:
Loop with x &= x - 1 counts bits per number [OK]
- Using built-in count_ones instead of algorithm
- Using trailing_zeros or leading_zeros which count zeros
- Not collecting results into a vector
Ready to prove it?
Pass the test and this pattern moves unknown
