{x}
blog image

Prime Number of Set Bits in Binary Representation

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.

  • For example, 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

Solution Explanation

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:

  1. 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).

  2. Checking for primality: Verifying if the count of set bits is present in the set of prime numbers defined earlier.

  3. Incrementing the count: If the count of set bits is prime, increment the final answer.

Code Explanation (Python)

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.
    • The generator expression yields a sequence of booleans (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 and Space Complexity Analysis

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.

Other Language Solutions

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.