Given two integers left
and right
, return the count of numbers in the inclusive range [left, right]
having a prime number of set bits in their binary representation.
Recall that the number of set bits an integer has is the number of 1
's present when written in binary.
21
written in binary is 10101
, which has 3
set bits.
Example 1:
Input: left = 6, right = 10 Output: 4 Explanation: 6 -> 110 (2 set bits, 2 is prime) 7 -> 111 (3 set bits, 3 is prime) 8 -> 1000 (1 set bit, 1 is not prime) 9 -> 1001 (2 set bits, 2 is prime) 10 -> 1010 (2 set bits, 2 is prime) 4 numbers have a prime number of set bits.
Example 2:
Input: left = 10, right = 15 Output: 5 Explanation: 10 -> 1010 (2 set bits, 2 is prime) 11 -> 1011 (3 set bits, 3 is prime) 12 -> 1100 (2 set bits, 2 is prime) 13 -> 1101 (3 set bits, 3 is prime) 14 -> 1110 (3 set bits, 3 is prime) 15 -> 1111 (4 set bits, 4 is not prime) 5 numbers have a prime number of set bits.
Constraints:
1 <= left <= right <= 106
0 <= right - left <= 104
The problem asks to count the numbers within a given range [left, right]
that have a prime number of set bits in their binary representation. A set bit is simply a 1
in the binary representation of a number.
The solution leverages the fact that the maximum number of set bits for a 32-bit integer is 32 (all bits are 1). Therefore, we only need to consider prime numbers up to 32. The prime numbers less than or equal to 32 are {2, 3, 5, 7, 11, 13, 17, 19}.
The core logic involves iterating through the numbers in the specified range and:
Counting set bits: Determining the number of set bits (1s) in the binary representation of each number. This can efficiently be done using built-in functions like Integer.bitCount()
(Java), bin().count('1')
(Python), __builtin_popcount()
(C++), or bits.OnesCount()
(Go).
Checking for primality: Verifying if the count of set bits is present in the set of prime numbers defined earlier.
Incrementing the count: If the count of set bits is prime, increment the final answer.
class Solution:
def countPrimeSetBits(self, left: int, right: int) -> int:
primes = {2, 3, 5, 7, 11, 13, 17, 19}
return sum(i.bit_count() in primes for i in range(left, right + 1))
This Python code is concise and efficient. It directly uses a generator expression within the sum()
function. Let's break it down:
primes = {2, 3, 5, 7, 11, 13, 17, 19}
: This line creates a set containing the prime numbers up to 32. Sets provide O(1) lookup time, making the primality check fast.sum(i.bit_count() in primes for i in range(left, right + 1))
: This is the core logic. It iterates through the numbers from left
to right
(inclusive). For each number i
:
i.bit_count()
: Counts the set bits in i
using Python's built-in method.... in primes
: Checks if the count of set bits is in the primes
set. This returns True
or False
.True
if the bit count is prime, False
otherwise).sum(...)
: Sums the booleans; True
is treated as 1 and False
as 0, effectively counting the numbers with a prime number of set bits.Time Complexity: O(n*log(k)), where n is the number of integers in the range [left, right], and k is the maximum number of bits in an integer (32 for 32-bit integers). The bit_count
operation has a time complexity of O(log k). In practice, bit_count
is highly optimized and might even be a constant time operation at the hardware level.
Space Complexity: O(1). The space used by the primes
set is constant, regardless of the input range. The generator expression is efficient and doesn't consume significant additional space.
The solutions provided in Java, C++, and Go follow a similar approach but utilize language-specific features for bit counting and set operations. The time and space complexity remain the same. They all use a set for efficient primality checking, and the main loop iterates once over the range [left, right]. The built-in functions for counting set bits are highly optimized in all languages.