Given an integer n, return an array ans of length n + 1 such that for each i (0 <= i <= n), ans[i] is the number of 1's in the binary representation of i.
Input: n = 2
Output: [0,1,1]
Explanation:
Input: n = 5
Output: [0,1,1,2,1,2]
Explanation:
O(n log n). Can you do it in linear time O(n) and possibly in a single pass?__builtin_popcount in C++)?The naive approach involves iterating over each number from 0 to n and calculating the number of 1's in its binary representation. This can be achieved by repeatedly dividing the number by 2 and counting the remainder when divided by 2.
A powerful way to compute the number of 1-bits for all numbers from 0 to n is to use a simple observation about binary numbers:
For any number i:
i >> 1) removes the last bit. This means i >> 1 is simply i / 2 (integer division). So i >> 1 has the same bits as i except for the least significant bit.i & 1 extracts the last bit of i.This allows us to build the result using previously computed values, making the solution both efficient and elegant.
Instead of counting bits from scratch for every number, we reuse the results from smaller numbers.
Let’s compute res[0..7]
res[0] = 0i = 1 → res[1] = res[0] + 1 = 1i = 2 → res[2] = res[1] + 0 = 1i = 3 → res[3] = res[1] + 1 = 2i = 4 → res[4] = res[2] + 0 = 1i = 5 → res[5] = res[2] + 1 = 2i = 6 → res[6] = res[3] + 0 = 2i = 7 → res[7] = res[3] + 1 = 3This approach relies on understanding how binary representations behave around powers of two.
For any number x, if it lies in the interval: 2^m ≤ x < 2^(m+1)
then we can express it as: x = 2^m + k where 0 ≤ k < 2^m
What does this mean in terms of set bits?
2^m has exactly one 1-bit, and it appears at position m.k, contains whatever lower bits x has.So the number of 1-bits in x becomes:
This allows us to reuse previously computed results from the range [0 … 2^m − 1].
We simply identify the most recent power of two, subtract it from x to get k, and use: