mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-12-19 07:00:35 +08:00
feat: add Count Set Bits algorithm (#7072)
* feat: add Count Set Bits algorithm (issue #6931) * fix: correct CountSetBits algorithm logic * style: apply clang-format to CountSetBits files * fix: correct test expectations for CountSetBits * fix: correct test expectations for CountSetBits
This commit is contained in:
committed by
GitHub
parent
3979e824b7
commit
93811614b8
@@ -1,79 +1,79 @@
|
||||
package com.thealgorithms.bitmanipulation;
|
||||
|
||||
public class CountSetBits {
|
||||
/**
|
||||
* Utility class to count total set bits from 1 to N
|
||||
* A set bit is a bit in binary representation that is 1
|
||||
*
|
||||
* @author navadeep
|
||||
*/
|
||||
public final class CountSetBits {
|
||||
|
||||
/**
|
||||
* The below algorithm is called as Brian Kernighan's algorithm
|
||||
* We can use Brian Kernighan’s algorithm to improve the above naive algorithm’s performance.
|
||||
The idea is to only consider the set bits of an integer by turning off its rightmost set bit
|
||||
(after counting it), so the next iteration of the loop considers the next rightmost bit.
|
||||
|
||||
The expression n & (n-1) can be used to turn off the rightmost set bit of a number n. This
|
||||
works as the expression n-1 flips all the bits after the rightmost set bit of n, including the
|
||||
rightmost set bit itself. Therefore, n & (n-1) results in the last bit flipped of n.
|
||||
|
||||
For example, consider number 52, which is 00110100 in binary, and has a total 3 bits set.
|
||||
|
||||
1st iteration of the loop: n = 52
|
||||
|
||||
00110100 & (n)
|
||||
00110011 (n-1)
|
||||
~~~~~~~~
|
||||
00110000
|
||||
|
||||
|
||||
2nd iteration of the loop: n = 48
|
||||
|
||||
00110000 & (n)
|
||||
00101111 (n-1)
|
||||
~~~~~~~~
|
||||
00100000
|
||||
|
||||
|
||||
3rd iteration of the loop: n = 32
|
||||
|
||||
00100000 & (n)
|
||||
00011111 (n-1)
|
||||
~~~~~~~~
|
||||
00000000 (n = 0)
|
||||
|
||||
* @param num takes Long number whose number of set bit is to be found
|
||||
* @return the count of set bits in the binary equivalent
|
||||
*/
|
||||
public long countSetBits(long num) {
|
||||
long cnt = 0;
|
||||
while (num > 0) {
|
||||
cnt++;
|
||||
num &= (num - 1);
|
||||
}
|
||||
return cnt;
|
||||
private CountSetBits() {
|
||||
// Utility class, prevent instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* This approach takes O(1) running time to count the set bits, but requires a pre-processing.
|
||||
* Counts total number of set bits in all numbers from 1 to n
|
||||
* Time Complexity: O(log n)
|
||||
*
|
||||
* So, we divide our 32-bit input into 8-bit chunks, with four chunks. We have 8 bits in each chunk.
|
||||
*
|
||||
* Then the range is from 0-255 (0 to 2^7).
|
||||
* So, we may need to count set bits from 0 to 255 in individual chunks.
|
||||
*
|
||||
* @param num takes a long number
|
||||
* @return the count of set bits in the binary equivalent
|
||||
* @param n the upper limit (inclusive)
|
||||
* @return total count of set bits from 1 to n
|
||||
* @throws IllegalArgumentException if n is negative
|
||||
*/
|
||||
public int lookupApproach(int num) {
|
||||
int[] table = new int[256];
|
||||
table[0] = 0;
|
||||
|
||||
for (int i = 1; i < 256; i++) {
|
||||
table[i] = (i & 1) + table[i >> 1]; // i >> 1 equals to i/2
|
||||
public static int countSetBits(int n) {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("Input must be non-negative");
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
res += table[num & 0xff];
|
||||
num >>= 8;
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
// Find the largest power of 2 <= n
|
||||
int x = largestPowerOf2InNumber(n);
|
||||
|
||||
// Total bits at position x: x * 2^(x-1)
|
||||
int bitsAtPositionX = x * (1 << (x - 1));
|
||||
|
||||
// Remaining numbers after 2^x
|
||||
int remainingNumbers = n - (1 << x) + 1;
|
||||
|
||||
// Recursively count for the rest
|
||||
int rest = countSetBits(n - (1 << x));
|
||||
|
||||
return bitsAtPositionX + remainingNumbers + rest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the position of the most significant bit in n
|
||||
*
|
||||
* @param n the number
|
||||
* @return position of MSB (0-indexed from right)
|
||||
*/
|
||||
private static int largestPowerOf2InNumber(int n) {
|
||||
int position = 0;
|
||||
while ((1 << position) <= n) {
|
||||
position++;
|
||||
}
|
||||
return position - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative naive approach - counts set bits by iterating through all numbers
|
||||
* Time Complexity: O(n log n)
|
||||
*
|
||||
* @param n the upper limit (inclusive)
|
||||
* @return total count of set bits from 1 to n
|
||||
*/
|
||||
public static int countSetBitsNaive(int n) {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("Input must be non-negative");
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int i = 1; i <= n; i++) {
|
||||
count += Integer.bitCount(i);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user