Bit Manipulation · 4 of 10
Count total set bits in all numbers from 1 to n
Count every 1 you would write if you wrote all numbers from 1 to n in binary, by counting each column with its repeating pattern.
- Simple way
- time O(n log n)
room O(1) - Clever way
- time O(log n)
room O(1)
The problem, simply
You get a number n. Write every number from 1 to n in binary. Count all the 1s you wrote, across all those numbers, and give back the total.
For n = 5: 1 is 1, 2 is 10, 3 is 11, 4 is 100, 5 is 101. That is 1 + 1 + 2 + 1 + 2 = 7 ones.
A story to remember it
Picture it
The numbers 0 to 6, one per row. Column 0 goes 0, 1, 0, 1. Column 1 goes 0, 0, 1, 1. Column 2 goes 0, 0, 0, 0, 1, 1, 1. Every column repeats blocks of zeros then ones.
Examples
A normal case
- In
n = 5- Out
7
1 + 1 + 2 + 1 + 2 = 7.
One less than a power of two
- In
n = 7- Out
12
0 to 7 fills all 3 columns completely. Each column is on for half the rows, 4 of 8, so the total is 3 times 4 = 12.
A bigger number
- In
n = 17- Out
35
Column 0 gives 9, column 1 gives 8, column 2 gives 8, column 3 gives 8, column 4 gives 2. That is 35.
The smallest inputs
- In
n = 1, n = 0- Out
1, 0
For 1 there is one 1. For 0 there are no numbers to write, so the answer is 0.
Way 1: the simple way
Do exactly what the problem says. For each number from 1 to n, count its 1s, and add them up.
- Loop
ifrom 1 ton. - Count the 1s in
iby checking the last bit and sliding right. - Add to the total.
class Solution {
public static long countTotalSetBits(int n) {
long total = 0;
for (int i = 1; i <= n; i++) {
int x = i;
while (x != 0) {
total += x & 1; // add 1 if the last bit is on
x >>>= 1;
}
}
return total;
}
}How long it takes: n numbers, each with up to log n bits, O(n log n). For n near a billion that is about 30 billion steps. Extra room: O(1).
Way 2: the clever way
Count down each column instead of across each row. Include 0 at the top, which adds no 1s but makes the patterns start cleanly. So there are n + 1 rows.
Column i repeats a block of 2^(i+1) rows: first 2^i zeros, then 2^i ones.
- Full blocks: there are
(n + 1) / 2^(i+1)of them, and each holds2^iones. - Left over rows: there are
(n + 1) % 2^(i+1)of them. The first2^iof those are zeros, so they addmax(0, leftover - 2^i)ones. - Add both parts for every column whose
2^iis at mostn.
Count column by column for n = 6
01 / 08
Write 0 to 6 in bits, one number per row. We add 0 on top because it has no 1s and it makes every pattern start cleanly. The plain way counts across each row. We will count down each column instead, because every column follows a simple pattern.
- n
- 6
- total
- 0
- checking
- done
- answer
- path
- just added
class Solution {
public static long countTotalSetBits(long n) {
long total = 0;
for (long half = 1; half <= n; half <<= 1) { // half = 2^i for column i
long block = half << 1; // zeros then ones, 2^(i+1) rows
long rows = n + 1; // the numbers 0 to n
total += (rows / block) * half; // full blocks
total += Math.max(0, rows % block - half); // the part that is left over
}
return total;
}
}How long it takes: one round per column, and n has about log n columns, O(log n). For a billion that is 30 rounds instead of 30 billion steps. Extra room: O(1).
Another way: split at the biggest power of two
Let 2^a be the biggest power of two that is at most n.
- The numbers from 0 to
2^a - 1fillacolumns completely, and each column is half ones, so they holda * 2^(a-1)ones. - Every number from
2^atonhas the top bit on. That isn - 2^a + 1more ones. - Under that top bit, those numbers count again from 0 to
n - 2^a. Solve that smaller problem the same way.
class Solution {
public static long countTotalSetBits(long n) {
if (n <= 0) return 0;
int a = 63 - Long.numberOfLeadingZeros(n); // 2^a is the biggest power of two <= n
long top = 1L << a;
long below = a == 0 ? 0 : (long) a << (a - 1); // a * 2^(a-1), all ones below 2^a
return below + (n - top + 1) + countTotalSetBits(n - top);
}
}Each call removes the top bit of n, so there are at most log n calls: O(log n) time and O(log n) room on the call stack.
Watch out for
- The left over part can be smaller than
2^i. Then it holds only zeros, so takemax(0, ...)instead of adding a negative number. - Totals grow fast, about
n log n / 2. Uselongfor the total. - In the split way,
a * 2^(a-1)must be 0 whena = 0. Guard it on its own: in Java a shift by -1 on alongmeans a shift by 63, which is never what you want.
What interviewers ask next
- Count 1s for every
ifrom 0 tonseparately? Build a table:bits[i] = bits[i >> 1] + (i & 1). That isO(n), and it is a classic. - Count only the 1s in column
kfrom 1 ton? That is one round of the loop above. - Count total 1s in a range from
LtoR? Answertotal(R) - total(L - 1). - Count numbers from 1 to
nwith exactlykset bits? Walk the bits ofnfrom the top and use combinations, a digit counting idea.
Remember this
Grown-up words: the bulbs are bit positions, the rhythm is a period of 2^(i+1), counting down columns is counting per bit position, and the split method is a divide and conquer on the most significant bit.