Given an integer n, count the number of 1's in the binary representation of every number in the range [0, n].
Return an array output where output[i] is the number of 1's in the binary representation of i.
Example 1:
Input: n = 4
Output: [0,1,1,2,1]Explanation:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
Constraints:
0 <= n <= 1000
You should aim for a solution with O(n) time and O(n) space, where n is the given integer.
A straightforward approach would be to iterate from 0 to n using i, and for each i, iterate through its bits to count the number of set bits. This would result in an O(n \log n) approach. Can you think of a better way? Maybe you should try identifying a pattern by observing the bitwise representation of consecutive numbers.
For example, to compute set bits for 7, add 1 to the count of set bits in 3, which was previously computed by adding 1 to the count of set bits in 1. Observing the pattern, for numbers less than 4, add 1 to the count from two positions before. For numbers less than 8, add 1 to the count from four positions before. Can you derive a dynamic programming relation from this?
We find an offset for the current number based on the number before offset positions. The dynamic programming relation is dp[i] = 1 + dp[i - offset], where dp[i] represents the number of set bits in i. The offset starts at 1 and updates when encountering a power of 2. To simplify the power of 2 check, if offset * 2 equals the current number, we update offset to the current number.
Before attempting this problem, you should be comfortable with:
For every number from 0 to n, we want to compute how many 1 bits appear in its binary representation.
This bit manipulation approach checks each bit position individually:
i is set using a bit maskAlthough this solution is not optimal, it clearly demonstrates how bitwise operations work at a low level.
res to store results.num from 0 to n:one = 0i from 0 to 31:i-th bit is set using (1 << i) & numoneone to resresTo count the number of 1 bits efficiently, we can use Brian Kernighan’s Algorithm.
The key observation:
n & (n - 1) removes the lowest set bit from nn becomes 0 counts how many 1 bits are presentThis avoids checking all 32 bits for every number.
res of size n + 1 initialized with 0.i from 1 to n:num = inum != 0:res[i]num &= (num - 1)res.We need to compute the number of set bits (1s) in the binary representation of every number from 0 to n.
Instead of manually counting bits using bit manipulation or dynamic programming, many programming languages provide built-in ways to convert numbers to binary or directly count set bits. Using these built-in features allows us to write a very concise and readable solution.
This approach is especially useful when:
n is small to moderatei from 0 to n:i to its binary representation using a built-in utility.1 bits in that representation.We want to compute the number of set bits (1s) for all numbers from 0 to n efficiently.
A key observation from binary representation is:
1 biti can be written as:i = highestPowerOfTwo ≤ i + remainderSo, the number of set bits in i is:
1 (for the highest power of two) + number of set bits in the remainder
This allows us to build the solution incrementally using Dynamic Programming, reusing results we have already computed.
dp of size n + 1dp[i] will store the number of set bits in idp[0] = 0offset = 1 (tracks the most recent power of two)i from 1 to n:i reaches the next power of two (i == 2 * offset):offset = idp[i] = 1 + dp[i - offset]We want to find the number of set bits (1s) in every number from 0 to n.
A very important observation from binary representation is:
i >> 1) removes the least significant bit(i & 1) tells us whether the last bit of i is 1 or 0So, the number of set bits in i can be built from a smaller number:
setBits(i) = setBits(i >> 1) + (i & 1)
This means each result depends only on a previously computed value, making it a perfect fit for Dynamic Programming.
dp of size n + 1dp[i] stores the number of set bits in idp[0] = 0i from 1 to n:i by 1 to get i >> 1(i & 1)dp[i] = dp[i >> 1] + (i & 1)When using the DP recurrence dp[i] = dp[i >> 1] + (i & 1), a common mistake is using left shift instead of right shift, or confusing the operator precedence.
# Wrong: Using left shift instead of right shift
dp[i] = dp[i << 1] + (i & 1) # This accesses invalid indices
# Wrong: Operator precedence issue in some languages
dp[i] = dp[i >> 1 + (i & 1)] # Addition happens before shift
# Correct
dp[i] = dp[i >> 1] + (i & 1)The problem asks for bits count from 0 to n inclusive, meaning the result array should have n + 1 elements. A common mistake is creating an array of size n or iterating up to n - 1.
# Wrong: Array too small
dp = [0] * n # Missing dp[n]
# Wrong: Loop doesn't include n
for i in range(n): # Should be range(n + 1)
# Correct
dp = [0] * (n + 1)
for i in range(n + 1):
# process