Problem
Given a non-negative integer n, return an array of length n + 1 where each position i holds the count of 1 bits in the binary representation of i. Think of it as building a lookup table of popcount values for every integer from 0 through n.
- Input: n = 5
- Output: [0, 1, 1, 2, 1, 2]
- Explanation: 5 in binary is
101(two 1-bits), 4 is100(one 1-bit), 3 is11(two 1-bits), and so on back to 0
Intuition
The straightforward path counts bits in each number from scratch. The key insight is that every number's bit count is already encoded in a smaller number you've visited: shifting right by one drops the lowest bit, so count(i) = count(i / 2) + (is i odd?). Because we fill the table from index 0 upward, every entry we need is already computed by the time we reach i.
Approach 1 โ Brute Force
For each number from 0 to n, count its 1-bits by repeatedly checking the lowest bit and right-shifting until nothing remains.
- Initialize an empty result array
- For each
numfrom 0 to n:- Copy
numinto a temporary variable so the loop variable stays intact - Count bits: while temp is non-zero, add the lowest bit and shift right
- Append the count to the result
- Copy
- Return result
1def countBits(n: int) -> list[int]:
2 result = []
3 for num in range(n + 1):
4 bit_count = 0
5 remaining = num # copy so we don't mutate the loop variable
6 while remaining:
7 bit_count += remaining & 1 # 1 if lowest bit is set, else 0
8 remaining >>= 1 # drop the lowest bit
9 result.append(bit_count)
10 return resultTime: O(n log n) โ each of the n+1 numbers requires up to logโ(n) shifts to fully process.
Space: O(1) extra โ only the output array is used.
Approach 2 โ Dynamic Programming
Reuse the bit count already stored for i >> 1: any number's popcount equals the popcount of half that number plus 1 if the number is odd.
- Allocate
bit_countof sizen + 1, all zeros - For each
ifrom 1 to n:bit_count[i] = bit_count[i >> 1] + (i & 1)i >> 1isiwith its lowest bit dropped (already in the table);i & 1adds that bit back if it was 1
- Return
bit_count
1def countBits(n: int) -> list[int]:
2 bit_count = [0] * (n + 1)
3 for i in range(1, n + 1):
4 bit_count[i] = bit_count[i >> 1] + (i & 1) # half of i is already in the table
5 return bit_countTime: O(n) โ exactly one constant-time operation per index.
Space: O(1) extra โ only the output array is used, no auxiliary structures.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Brute Force | O(n log n) | O(1) extra | Learning bit operations or n is trivially small |
| DP (bit shift) | O(n) | O(1) extra | Always โ same memory footprint, strictly faster |
Common Mistakes
- Allocating n elements instead of n+1: the output spans indices 0 through n inclusive โ
new int[n]is one entry short and causes an out-of-bounds write at the last step. - Left shift instead of right:
i << 1doubles i and jumps past the computed table; the recurrence needsi >> 1to look up the answer fori / 2. - Mutating the loop variable in brute force: writing
while num: num >>= 1overwrites the index โ always copy into a temporary likeremaining = numbefore the inner loop. - Wrong bit selector:
i & 1checks whether the lowest bit is set (i.e., whether i is odd); usingi & 2instead checks the second bit, producing wrong counts for every odd number. - Misplacing dp[0]: the base case
bit_count[0] = 0is automatically correct in every language's default initialization โ manually setting it to 1 breaks every even number built on top of it.
Related Problems
number-of-1-bitsโ counts popcount for a single integer, the building block that this problem reuses across a rangesingle-numberโ uses XOR properties to isolate an unpaired element, another classic bit identitymissing-numberโ XOR or math trick to find the gap in a sequence, same bit-manipulation mindsetreverse-bitsโ mirrors individual bits of a 32-bit integer, requiring the same shift-and-mask intuitionbitwise-and-of-numbers-rangeโ finds the common bit prefix of a range, combining similar shift-based reasoning at the range level