Problem
Write a function that takes the binary representation of a positive integer and returns the number of set bits it has (also known as the Hamming weight).
Note:
- Note that in some languages, such as Java, there is no unsigned integer type. In this case, the input will be given as a signed integer type. It should not affect your implementation, as the integer’s internal binary representation is the same, whether it is signed or unsigned.
- In Java, the compiler represents the signed integers using 2’s complement notation. Therefore, in Example 3, the input represents the signed integer.
-3
.
Examples
Example 1:
|
|
Example 2:
|
|
Example 3:
|
|
Solution
Video explanation
Here is the video explaining this method in detail. Please check it out:
Method 1 - Using Modulus and Divide by 2
The basic approach to evaluate the binary form of a number is to traverse on it and count the number of ones.
As to get a number in its binary form, we have to divide it by 2, until it gets 0, which will take logN of time.
Example
|
|
Code
|
|
Complexity
- ⏰ Time complexity: $O(log_2n)$. Given it is a 32 bit integer, O (log (2^32)) = O(32) = O(1)
- 🧺 Space complexity:
O(1)
Method 2 - Using Right Shift Instead of Division
Code
|
|
Complexity
- ⏰ Time complexity: $O(log_2n)$. Given it is a 32 bit integer, O (log (2^32)) = O(32) = O(1)
- 🧺 Space complexity:
O(1)
Method 3 - Using Right Shift and & Operator
We can also use &
operator to do the count in previous method, rather than mod. Here we are checking if after right shift, we have 1 at the rightmost position using mask = 1.
Code
|
|
Complexity
- ⏰ Time complexity: $O(log_2n)$. Given it is a 32 bit integer, O (log (2^32)) = O(32) = O(1)
- 🧺 Space complexity:
O(1)
Method 4 - Brian Kernighan’s Algorithm Using & Operator OR Hamming Distance Method 🥇
Video explanation
Here is the video explaining this method in detail. Please check it out:
Code
|
|
Complexity
- ⏰ Time complexity: O(K), where where K is the number of ones present in the binary form of the given number. Given it is a 32 bit integer, O (log (2^32)) = O(32) = O(1)
- 🧺 Space complexity:
O(1)
Why this works?
Read here - x&(x-1) Explained.
So as in x-1, the rightmost 1 and bits right to it are flipped, then by performing x&(x-1), and storing it in x, will reduce x to a number containing number of ones(in its binary form) less than the previous state of x, thus increasing the value of count in each iteration.
Dry Run
Suppose, n = 23 = 0b10111
- Initial State:
n = 23 (10111 in binary)
.count = 0
(to store the number of set bits).
- Iterative Steps:
- n = 23 =
10111
, n - 1 = 22 =10110
.n & (n - 1) = 10111 & 10110 = 10110
= 22. - n = 22 =
10110
, n - 1 = 21 =10101
.n & (n - 1) = 10110 & 10101 = 10100
= 20. - n = 20 =
10100
, n - 1 = 19 =10011
.n & (n - 1) = 10100 & 10011 = 100000
= 16. - n = 16 =
100000
, n - 1 = 19 =01111
.n & (n - 1) = 100000 & 01111 = 00000
= 0.
- n = 23 =
As, now, n = 0, we return 4
as we count the bits each time, n & (n - 1)
changes bits.
Method 4 - Using Bitwise And Operator and Left Shift
Code
|
|
Method 5 - Using Lookup Table
This method gains efficiency by leveraging a pre-computed lookup table. The table stores the number of set bits for every integer from 0 to 255, eliminating the need for runtime calculation.
For example:
|
|
Code
|
|
Complexity
- ⏰ Time complexity:
O(1)
- 🧺 Space complexity:
O(256)
=O(1)
Please see http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable for details.
Method 6 -From Hacker’s Delight, p. 66, Figure 5-2
Code
|
|
|
|
Method 7 - Divide and Conquer
This algorithm is based on Divide and Conquer Algorithm. Suppose there is a 8bit integer 213(11010101 in binary), the algorithm works like this(each time merge two neighbor blocks):
|
|
Code
|
|
Method 8 - XOR the number and -negative of number, till number becomes 0
Code
|
|
Method 9 - Converting number to string and counting 1s
Code
|
|