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.
Example 1:
Input: n = 2
Output: [0,1,1]
Explanation:
0 --> 0 (0 '1' bits)
1 --> 1 (1 '1' bit)
2 --> 10 (1 '1' bit)
Example 2:
Input: n = 5
Output: [0,1,1,2,1,2]
Explanation:
0 --> 0 (0 '1' bits)
1 --> 1 (1 '1' bit)
2 --> 10 (1 '1' bit)
3 --> 11 (2 '1' bits)
4 --> 100 (1 '1' bit)
5 --> 101 (2 '1' bits)
The key insight for this problem is to recognize that the number of 1 bits in a number can be calculated using previously computed results. There are several patterns we can exploit:
-
Least Significant Bit (LSB) Pattern: The number of 1 bits in
iequals the number of 1 bits ini >> 1(i.e.,idivided by 2) plus the value of the least significant bit ofi(i.e.,i & 1). -
Power of Two Pattern: For a power of 2, there is exactly one 1 bit. For numbers between consecutive powers of 2, we can use previously computed results.
-
Offset Pattern: The number of 1 bits in
iequals the number of 1 bits ini - offsetplus 1, whereoffsetis the largest power of 2 less than or equal toi.
We'll use the first pattern (LSB) for our solution as it's the most intuitive and efficient.
Let's visualize the LSB pattern for n = 5:
i = 0: Binary = 0
i >> 1 = 0, Binary = 0
LSB = 0 & 1 = 0
Count = count[0 >> 1] + (0 & 1) = count[0] + 0 = 0 + 0 = 0
i = 1: Binary = 1
i >> 1 = 0, Binary = 0
LSB = 1 & 1 = 1
Count = count[1 >> 1] + (1 & 1) = count[0] + 1 = 0 + 1 = 1
i = 2: Binary = 10
i >> 1 = 1, Binary = 1
LSB = 2 & 1 = 0
Count = count[2 >> 1] + (2 & 1) = count[1] + 0 = 1 + 0 = 1
i = 3: Binary = 11
i >> 1 = 1, Binary = 1
LSB = 3 & 1 = 1
Count = count[3 >> 1] + (3 & 1) = count[1] + 1 = 1 + 1 = 2
i = 4: Binary = 100
i >> 1 = 2, Binary = 10
LSB = 4 & 1 = 0
Count = count[4 >> 1] + (4 & 1) = count[2] + 0 = 1 + 0 = 1
i = 5: Binary = 101
i >> 1 = 2, Binary = 10
LSB = 5 & 1 = 1
Count = count[5 >> 1] + (5 & 1) = count[2] + 1 = 1 + 1 = 2
- Initialize an array
ansof sizen + 1with all zeros. - Set
ans[0] = 0since 0 has no 1 bits. - For each number
ifrom 1 ton:- Calculate the number of 1 bits using the formula:
ans[i] = ans[i >> 1] + (i & 1).
- Calculate the number of 1 bits using the formula:
- Return the
ansarray.
def countBits(n):
# Initialize the result array with 0s
ans = [0] * (n + 1)
# For each number from 1 to n
for i in range(1, n + 1):
# Number of 1 bits = number of 1 bits in i//2 + least significant bit
ans[i] = ans[i >> 1] + (i & 1)
return ansfunction countBits(n) {
// Initialize the result array with 0s
const ans = new Array(n + 1).fill(0);
// For each number from 1 to n
for (let i = 1; i <= n; i++) {
// Number of 1 bits = number of 1 bits in i//2 + least significant bit
ans[i] = ans[i >> 1] + (i & 1);
}
return ans;
}Another approach is to use Brian Kernighan's algorithm, which counts the number of set bits by repeatedly removing the rightmost set bit.
def countBits(n):
ans = [0] * (n + 1)
for i in range(1, n + 1):
count = 0
num = i
while num:
num &= (num - 1) # Clear the least significant set bit
count += 1
ans[i] = count
return ansfunction countBits(n) {
const ans = new Array(n + 1).fill(0);
for (let i = 1; i <= n; i++) {
let count = 0;
let num = i;
while (num) {
num &= (num - 1); // Clear the least significant set bit
count++;
}
ans[i] = count;
}
return ans;
}- Time Complexity: O(n), where n is the input integer. We iterate through each number from 0 to n once.
- Space Complexity: O(n) for the result array.
- Time Complexity: O(n * log n), where n is the input integer. For each number, we perform at most log(n) operations to count the set bits.
- Space Complexity: O(n) for the result array.
Let's trace through the dynamic programming approach with n = 5:
Initialize ans = [0, 0, 0, 0, 0, 0]
i = 1:
ans[1] = ans[1 >> 1] + (1 & 1) = ans[0] + 1 = 0 + 1 = 1
ans = [0, 1, 0, 0, 0, 0]
i = 2:
ans[2] = ans[2 >> 1] + (2 & 1) = ans[1] + 0 = 1 + 0 = 1
ans = [0, 1, 1, 0, 0, 0]
i = 3:
ans[3] = ans[3 >> 1] + (3 & 1) = ans[1] + 1 = 1 + 1 = 2
ans = [0, 1, 1, 2, 0, 0]
i = 4:
ans[4] = ans[4 >> 1] + (4 & 1) = ans[2] + 0 = 1 + 0 = 1
ans = [0, 1, 1, 2, 1, 0]
i = 5:
ans[5] = ans[5 >> 1] + (5 & 1) = ans[2] + 1 = 1 + 1 = 2
ans = [0, 1, 1, 2, 1, 2]
Return ans = [0, 1, 1, 2, 1, 2]
- n = 0: The result is [0], which is handled correctly by our implementation.
- Large n: The solution scales well for large n, with O(n) time complexity.
Optimization: We can use bit manipulation to optimize the solution further. The formula ans[i] = ans[i >> 1] + (i & 1) already uses bit manipulation for efficiency.
- Not handling the base case: Make sure to initialize ans[0] = 0.
- Using a less efficient algorithm: Using a naive approach to count bits for each number would result in O(n * log n) time complexity.
- Off-by-one errors: Be careful with the array size and loop bounds.
- Number of 1 Bits: Count the number of 1 bits in a single integer.
- Power of Two: Determine if a number is a power of two.
- Bitwise AND of Numbers Range: Find the bitwise AND of all numbers in a range.
- Single Number: Find the number that appears only once in an array where all other numbers appear twice.
