Problem
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
.
Examples
Example 1:
|
|
Example 2:
|
|
Solution
Video explanation
Here is the video explaining below methods in detail. Please check it out:
Method 1 - Naive
Here is the naive approach:
- Loop through all integers from
0
ton
. - For each integer, count the number of 1’s in its binary representation using repeated division by 2 (to extract each bit).
- Store the count for the integer in the result array.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n log n)
, log N time to findcountOnes
as we divide number logN times and we have to do it for n numbers. - 🧺 Space complexity:
O(1)
Method 2 - DP following power of 2
This method focuses on leveraging the properties of powers of 2. Every power of 2 (2^m
) has exactly one set bit in its binary representation at mth
position. Non-power-of-2 numbers can be expressed as:
|
|
where r
is the remainder. By observing this, we can relate the set bits of these numbers to their remainder.
Now, suppose n = 10. For that lets look at the numbers from 1 to 10:
Number | Binary Representation | Number of Set bits |
---|---|---|
0 | 0 |
0 |
1 | 1 |
1 |
2 | 10 |
1 |
3 | 11 |
2 |
4 | 100 |
1 |
5 | 101 |
2 |
6 | 110 |
2 |
7 | 111 |
3 |
8 | 1000 |
1 |
9 | 1001 |
2 |
10 | 1010 |
2 |
From the table, we can see the pattern emerge for calculating the count of set bits (dp[i] ) for each number. |
So, dp[0] = 0
is the base case.
Here’s how the recurrence relation applies:
dp[0] = 0
(base case)dp[1] = dp[0] + 1 ⇨ 1 + dp[i - 1]
dp[2] = dp[0] + 1 ⇨ 1 + dp[i - 2]
dp[3] = dp[1] + 1 ⇨ 1 + dp[i - 2]
dp[4] = dp[0] + 1 ⇨ 1 + dp[i - 4]
dp[5] = dp[1] + 1 ⇨ 1 + dp[i - 4]
dp[6] = dp[2] + 1 ⇨ 1 + dp[i - 4]
dp[7] = dp[3] + 1 ⇨ 1 + dp[i - 4]
dp[8] = dp[0] + 1 ⇨ 1 + dp[i - 8]
dp[9] = dp[1] + 1 ⇨ 1 + dp[i - 8]
dp[10] = dp[2] + 1 ⇨ 1 + dp[i - 8]
The offset corresponds to the nearest power of 2 for each number. As soon as we reach the next power of 2 (2, 4, 8, ...
), we update the offset to that power of 2. This avoids recalculating results unnecessarily.
Using this insight, we can iterate through numbers from 1
to n
(starting with the base case dp[0] = 0
) and compute the count of set bits for each number using this recurrence formula:
$$ dp[i] = dp[i - offset] + 1 $$
Where offset
is the largest power of 2 less than or equal to i
.
Approach
- Use dynamic programming to compute set bits iteratively by tracking the
offset
, which is the largest power of 2 less than or equal to the current number. - For each number
i
, use the recurrence relation: $$ dp[i] = dp[i - offset] + 1 $$ Here,offset
corresponds to2^m
, the largest power of 2 encountered so far. - Incrementally compute results by reusing those from smaller subproblems (numbers closer to powers of 2).
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n)
. The algorithm iterates through numbers from1
ton
, performing a constant-time calculation for each number based on the recurrence relation. Thus, the time complexity isO(n)
. - 🧺 Space complexity:
O(n)
. The algorithm uses an arraydp
of sizen + 1
to store the set bit counts for each number. Hence, the space complexity isO(n)
.
Method 3 - Using DP based on division by 2
We can refine the solution further by focusing solely on how the number x
changes after dividing the number by 2 which is same as right shifting the number by 1.
Lets take 2 numbers x
and y
where x / 2 = y
. Now, there are 2 main cases.
- Case 1:
x
is Even- When
x
is even, its least significant bit (LSB) is0
. - Dividing
x
by 2 (or right-shifting it) givesy
, which has the same number of set bits asx
. - For example:
x = 6 (110)
andy = 3 (011)
6 / 2 = 3
- Both
6
and3
have the same number of set bits (2 set bits in this case).
- When
- Case 2:
x
is Odd- When
x
is odd, its least significant bit (LSB) is1
. - Dividing
x
by 2 (or right-shifting it) givesy
, and the number of set bits inx
is1
more than iny
. - For example:
x = 7 (111)
andy = 3 (011)
7 / 2 = 3
Number of set bits in 7 = 3
, whileNumber of set bits in 3 = 2
.
- When
From these cases, we can define the recurrence relation as:
$$ dp[i] = dp[i/2] + i \mod 2 $$
This uses simple arithmetic to determine whether the least significant bit contributes an additional 1
.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n)
. The loop runs from1
ton
, and each computation(bitwise AND and right shift) takes constant time (O(1)
). - 🧺 Space complexity:
O(n)
. We maintain an array to store the results for all numbers up ton
.
Method 4 - Using DP based on division by 2 but fully bitwise
Alternatively, as shown in the Number of 1 Bits problem, we can express this with binary operators for efficiency:
$$ ans[i] = ans[i \gg 1] + (i & 1) $$
i >> 1
: This shifts the numberi
to the right by 1 bit (essentially dividingi
by 2), leveraging previously computed results.(i & 1)
: Checks if the last bit ofi
is 1 (which checks whetheri
is odd).
So,
- If
i
is even: There is no additional1
in its binary representation compared toi >> 1
. - If
i
is odd: There is exactly one additional1
compared toi >> 1
.
Approach
dp[0] = 0
(base case, 0 has no set bits).- For each number
i
from 1 ton
, computedp[i]
using the transition function above.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n)
. The loop runs forn
computations, and each computation takes constant time, hence it isO(n)
. - 🧺 Space complexity:
O(n)
used bydp
array.