Implement countOnesInBinary(n) — given a non-negative integer, return how many 1 bits appear in its binary representation. The number 13 is 1101 in binary, so it has three 1 bits and the answer is 3. This count goes by several names you'll see in the wild: the Hamming weight, the population count (or popcount), and the number of set bits. A set bit just means a bit position holding a 1 rather than a 0.
// n: a non-negative integer (0, 1, 2, ...).
// returns: the number of 1 bits in n's binary form, as a number.
function countOnesInBinary(n: number): number;
countOnesInBinary(0); // → 0 (binary 0, no 1 bits)
countOnesInBinary(7); // → 3 (binary 111, three 1 bits)
countOnesInBinary(8); // → 1 (binary 1000, one 1 bit)
countOnesInBinary(255); // → 8 (binary 11111111, eight 1 bits)
n is a non-negative integer. You don't need to handle negative numbers or non-integers.0 has zero set bits. The smallest input returns 0 — make sure your loop handles it without entering the body.1, 2, 4, 8, 16 each return 1; only the position of the single bit changes.1 bits, not the bit length. 8 is four bits wide (1000) but only one of them is set, so the answer is 1, not 4.You'll count how many 1 bits a number has by repeatedly knocking out its lowest set bit and tallying each one you remove.
Every non-negative integer has a binary form — a row of 0s and 1s. 13 is 1101, 8 is 1000, 255 is 11111111. Your job is to report how many of those digits are 1. Picture a row of light switches where each switch is on (1) or off (0): you're counting how many are on. The catch the question is really testing is how you count — the obvious way looks at every switch, but a sharper way looks only at the ones that are on.
Hold two things in your head: the number n, and a running count. You want to shrink n down to 0 while bumping count once for each set bit you eliminate. The naive approach walks one bit position at a time; the sharper approach jumps straight from one set bit to the next, skipping every 0 in between. The whole trick rests on one identity: subtracting 1 from a number flips its lowest 1 bit to 0 and turns every 0 below it into a 1. AND-ing that back against the original keeps only the bits they still share — which means the lowest 1 disappears and nothing else changes.
The instinct is to inspect the number one bit at a time: check whether the lowest bit is 1, add it to the count, then shift the number right to expose the next bit.
function countOnesInBinary(n) {
let count = 0;
while (n !== 0) {
count += n & 1; // is the lowest bit a 1? add 0 or 1
n >>= 1; // drop the lowest bit, expose the next one
}
return count;
}
This is correct — it returns the right answer for every input. But it does one loop iteration per bit position, not per set bit. For a number like 8 (1000), it spins four times even though only one bit is set, and n & 1 is 0 on three of those passes. The work scales with how wide the number is, not with how many 1s it actually contains. For sparse numbers — a single high bit in a 32-bit word — that's a lot of wasted spins checking zeros.
function countOnesInBinary(n) {
let count = 0;
// Loop runs once per SET bit, not once per bit position. Each pass below
// removes exactly one 1 from n, so a number with three 1s loops three times.
while (n !== 0) {
// n - 1 flips n's lowest 1 to 0 and all the 0s below it to 1s. AND-ing
// with n keeps only the bits they share, which clears that lowest 1 and
// leaves every higher bit untouched. One set bit gone per pass.
n &= n - 1;
count++;
}
return count;
}
module.exports = { countOnesInBinary };
The shift is the loop body. Instead of stepping past every position and asking "is this one set?", n &= n - 1 teleports straight to the next set bit by deleting the current lowest one. The loop condition n !== 0 is now satisfied exactly as many times as there are 1s: each pass removes one, so the loop ends the moment the last 1 is cleared. This is Brian Kernighan's algorithm, and it runs in time proportional to the number of set bits rather than the number of bit positions.
Trace countOnesInBinary(13). In binary, 13 is 1101, so we expect 3.
n = 1101, count = 0
pass 1: n - 1 = 1100, n & (n-1) = 1101 & 1100 = 1100 → count = 1
pass 2: n - 1 = 1011, n & (n-1) = 1100 & 1011 = 1000 → count = 2
pass 3: n - 1 = 0111, n & (n-1) = 1000 & 0111 = 0000 → count = 3
n is now 0 → loop exits → return 3
Each pass erases the lowest remaining 1: first the bit worth 1, then the bit worth 4, then the bit worth 8. The 0 in the middle is never visited on its own — the algorithm jumps over it for free. Three set bits, three passes, answer 3.
n !== 0, not while n > 0. For non-negative inputs both work, but !== 0 is the honest condition: the loop's real job is to run until every bit is cleared. Anchor on "stop when n is 0," which is exactly what n &= n - 1 drives toward.0 skips the loop entirely. countOnesInBinary(0) never enters the while body because n is already 0, so count stays 0 and is returned. That's the correct answer — don't add a special case for it.n occupies (e.g. Math.floor(Math.log2(n)) + 1) and call that the answer. That's the length, not the count of 1s. 8 is four bits wide but has only one set bit.n.toString(2) and counting characters. n.toString(2).split('').filter((c) => c === '1').length works and is readable, but it allocates a string and scans every character — the same per-position cost as the naive loop, plus string overhead. Fine for clarity; n &= n - 1 is the technique an interviewer is fishing for.&, -, and >> coerce their operands to signed 32-bit integers, so this approach is exact for values up to 2 ** 31 - 1. Beyond that you'd need BigInt or to mask with >>> 0. For the non-negative integers in this question's range, the plain operators are correct.__builtin_popcount, Python int.bit_count(), Java Integer.bitCount. JavaScript has none natively, but WebAssembly exposes i32.popcnt. Knowing the name lets you reach for the fast path when the platform offers it.0x55555555 and 0x33333333. It's how popcount is often implemented in hardware-free environments — worth studying once you're comfortable with masking.Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.
Implement countOnesInBinary(n) — given a non-negative integer, return how many 1 bits appear in its binary representation. The number 13 is 1101 in binary, so it has three 1 bits and the answer is 3. This count goes by several names you'll see in the wild: the Hamming weight, the population count (or popcount), and the number of set bits. A set bit just means a bit position holding a 1 rather than a 0.
// n: a non-negative integer (0, 1, 2, ...).
// returns: the number of 1 bits in n's binary form, as a number.
function countOnesInBinary(n: number): number;
countOnesInBinary(0); // → 0 (binary 0, no 1 bits)
countOnesInBinary(7); // → 3 (binary 111, three 1 bits)
countOnesInBinary(8); // → 1 (binary 1000, one 1 bit)
countOnesInBinary(255); // → 8 (binary 11111111, eight 1 bits)
n is a non-negative integer. You don't need to handle negative numbers or non-integers.0 has zero set bits. The smallest input returns 0 — make sure your loop handles it without entering the body.1, 2, 4, 8, 16 each return 1; only the position of the single bit changes.1 bits, not the bit length. 8 is four bits wide (1000) but only one of them is set, so the answer is 1, not 4.You'll count how many 1 bits a number has by repeatedly knocking out its lowest set bit and tallying each one you remove.
Every non-negative integer has a binary form — a row of 0s and 1s. 13 is 1101, 8 is 1000, 255 is 11111111. Your job is to report how many of those digits are 1. Picture a row of light switches where each switch is on (1) or off (0): you're counting how many are on. The catch the question is really testing is how you count — the obvious way looks at every switch, but a sharper way looks only at the ones that are on.
Hold two things in your head: the number n, and a running count. You want to shrink n down to 0 while bumping count once for each set bit you eliminate. The naive approach walks one bit position at a time; the sharper approach jumps straight from one set bit to the next, skipping every 0 in between. The whole trick rests on one identity: subtracting 1 from a number flips its lowest 1 bit to 0 and turns every 0 below it into a 1. AND-ing that back against the original keeps only the bits they still share — which means the lowest 1 disappears and nothing else changes.
The instinct is to inspect the number one bit at a time: check whether the lowest bit is 1, add it to the count, then shift the number right to expose the next bit.
function countOnesInBinary(n) {
let count = 0;
while (n !== 0) {
count += n & 1; // is the lowest bit a 1? add 0 or 1
n >>= 1; // drop the lowest bit, expose the next one
}
return count;
}
This is correct — it returns the right answer for every input. But it does one loop iteration per bit position, not per set bit. For a number like 8 (1000), it spins four times even though only one bit is set, and n & 1 is 0 on three of those passes. The work scales with how wide the number is, not with how many 1s it actually contains. For sparse numbers — a single high bit in a 32-bit word — that's a lot of wasted spins checking zeros.
function countOnesInBinary(n) {
let count = 0;
// Loop runs once per SET bit, not once per bit position. Each pass below
// removes exactly one 1 from n, so a number with three 1s loops three times.
while (n !== 0) {
// n - 1 flips n's lowest 1 to 0 and all the 0s below it to 1s. AND-ing
// with n keeps only the bits they share, which clears that lowest 1 and
// leaves every higher bit untouched. One set bit gone per pass.
n &= n - 1;
count++;
}
return count;
}
module.exports = { countOnesInBinary };
The shift is the loop body. Instead of stepping past every position and asking "is this one set?", n &= n - 1 teleports straight to the next set bit by deleting the current lowest one. The loop condition n !== 0 is now satisfied exactly as many times as there are 1s: each pass removes one, so the loop ends the moment the last 1 is cleared. This is Brian Kernighan's algorithm, and it runs in time proportional to the number of set bits rather than the number of bit positions.
Trace countOnesInBinary(13). In binary, 13 is 1101, so we expect 3.
n = 1101, count = 0
pass 1: n - 1 = 1100, n & (n-1) = 1101 & 1100 = 1100 → count = 1
pass 2: n - 1 = 1011, n & (n-1) = 1100 & 1011 = 1000 → count = 2
pass 3: n - 1 = 0111, n & (n-1) = 1000 & 0111 = 0000 → count = 3
n is now 0 → loop exits → return 3
Each pass erases the lowest remaining 1: first the bit worth 1, then the bit worth 4, then the bit worth 8. The 0 in the middle is never visited on its own — the algorithm jumps over it for free. Three set bits, three passes, answer 3.
n !== 0, not while n > 0. For non-negative inputs both work, but !== 0 is the honest condition: the loop's real job is to run until every bit is cleared. Anchor on "stop when n is 0," which is exactly what n &= n - 1 drives toward.0 skips the loop entirely. countOnesInBinary(0) never enters the while body because n is already 0, so count stays 0 and is returned. That's the correct answer — don't add a special case for it.n occupies (e.g. Math.floor(Math.log2(n)) + 1) and call that the answer. That's the length, not the count of 1s. 8 is four bits wide but has only one set bit.n.toString(2) and counting characters. n.toString(2).split('').filter((c) => c === '1').length works and is readable, but it allocates a string and scans every character — the same per-position cost as the naive loop, plus string overhead. Fine for clarity; n &= n - 1 is the technique an interviewer is fishing for.&, -, and >> coerce their operands to signed 32-bit integers, so this approach is exact for values up to 2 ** 31 - 1. Beyond that you'd need BigInt or to mask with >>> 0. For the non-negative integers in this question's range, the plain operators are correct.__builtin_popcount, Python int.bit_count(), Java Integer.bitCount. JavaScript has none natively, but WebAssembly exposes i32.popcnt. Knowing the name lets you reach for the fast path when the platform offers it.0x55555555 and 0x33333333. It's how popcount is often implemented in hardware-free environments — worth studying once you're comfortable with masking.Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.