Skip to content

Commit 8931014

Browse files
authored
Merge branch 'master' into add-sudoku-solver
2 parents 2b0ced0 + c6880c1 commit 8931014

File tree

4 files changed

+196
-132
lines changed

4 files changed

+196
-132
lines changed
Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,79 @@
11
package com.thealgorithms.bitmanipulation;
22

3-
public class CountSetBits {
3+
/**
4+
* Utility class to count total set bits from 1 to N
5+
* A set bit is a bit in binary representation that is 1
6+
*
7+
* @author navadeep
8+
*/
9+
public final class CountSetBits {
10+
11+
private CountSetBits() {
12+
// Utility class, prevent instantiation
13+
}
414

515
/**
6-
* The below algorithm is called as Brian Kernighan's algorithm
7-
* We can use Brian Kernighan’s algorithm to improve the above naive algorithm’s performance.
8-
The idea is to only consider the set bits of an integer by turning off its rightmost set bit
9-
(after counting it), so the next iteration of the loop considers the next rightmost bit.
10-
11-
The expression n & (n-1) can be used to turn off the rightmost set bit of a number n. This
12-
works as the expression n-1 flips all the bits after the rightmost set bit of n, including the
13-
rightmost set bit itself. Therefore, n & (n-1) results in the last bit flipped of n.
14-
15-
For example, consider number 52, which is 00110100 in binary, and has a total 3 bits set.
16-
17-
1st iteration of the loop: n = 52
18-
19-
00110100 & (n)
20-
00110011 (n-1)
21-
~~~~~~~~
22-
00110000
16+
* Counts total number of set bits in all numbers from 1 to n
17+
* Time Complexity: O(log n)
18+
*
19+
* @param n the upper limit (inclusive)
20+
* @return total count of set bits from 1 to n
21+
* @throws IllegalArgumentException if n is negative
22+
*/
23+
public static int countSetBits(int n) {
24+
if (n < 0) {
25+
throw new IllegalArgumentException("Input must be non-negative");
26+
}
2327

28+
if (n == 0) {
29+
return 0;
30+
}
2431

25-
2nd iteration of the loop: n = 48
32+
// Find the largest power of 2 <= n
33+
int x = largestPowerOf2InNumber(n);
2634

27-
00110000 & (n)
28-
00101111 (n-1)
29-
~~~~~~~~
30-
00100000
35+
// Total bits at position x: x * 2^(x-1)
36+
int bitsAtPositionX = x * (1 << (x - 1));
3137

38+
// Remaining numbers after 2^x
39+
int remainingNumbers = n - (1 << x) + 1;
3240

33-
3rd iteration of the loop: n = 32
41+
// Recursively count for the rest
42+
int rest = countSetBits(n - (1 << x));
3443

35-
00100000 & (n)
36-
00011111 (n-1)
37-
~~~~~~~~
38-
00000000 (n = 0)
44+
return bitsAtPositionX + remainingNumbers + rest;
45+
}
3946

40-
* @param num takes Long number whose number of set bit is to be found
41-
* @return the count of set bits in the binary equivalent
42-
*/
43-
public long countSetBits(long num) {
44-
long cnt = 0;
45-
while (num > 0) {
46-
cnt++;
47-
num &= (num - 1);
47+
/**
48+
* Finds the position of the most significant bit in n
49+
*
50+
* @param n the number
51+
* @return position of MSB (0-indexed from right)
52+
*/
53+
private static int largestPowerOf2InNumber(int n) {
54+
int position = 0;
55+
while ((1 << position) <= n) {
56+
position++;
4857
}
49-
return cnt;
58+
return position - 1;
5059
}
5160

5261
/**
53-
* This approach takes O(1) running time to count the set bits, but requires a pre-processing.
62+
* Alternative naive approach - counts set bits by iterating through all numbers
63+
* Time Complexity: O(n log n)
5464
*
55-
* So, we divide our 32-bit input into 8-bit chunks, with four chunks. We have 8 bits in each chunk.
56-
*
57-
* Then the range is from 0-255 (0 to 2^7).
58-
* So, we may need to count set bits from 0 to 255 in individual chunks.
59-
*
60-
* @param num takes a long number
61-
* @return the count of set bits in the binary equivalent
65+
* @param n the upper limit (inclusive)
66+
* @return total count of set bits from 1 to n
6267
*/
63-
public int lookupApproach(int num) {
64-
int[] table = new int[256];
65-
table[0] = 0;
66-
67-
for (int i = 1; i < 256; i++) {
68-
table[i] = (i & 1) + table[i >> 1]; // i >> 1 equals to i/2
68+
public static int countSetBitsNaive(int n) {
69+
if (n < 0) {
70+
throw new IllegalArgumentException("Input must be non-negative");
6971
}
7072

71-
int res = 0;
72-
for (int i = 0; i < 4; i++) {
73-
res += table[num & 0xff];
74-
num >>= 8;
73+
int count = 0;
74+
for (int i = 1; i <= n; i++) {
75+
count += Integer.bitCount(i);
7576
}
76-
77-
return res;
77+
return count;
7878
}
7979
}
Lines changed: 57 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,82 @@
11
package com.thealgorithms.maths;
22

3-
import java.util.Arrays;
3+
import java.util.ArrayList;
4+
import java.util.List;
45

56
/**
6-
* @brief utility class implementing <a href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes">Sieve of Eratosthenes</a>
7+
* Sieve of Eratosthenes Algorithm
8+
* An efficient algorithm to find all prime numbers up to a given limit.
9+
*
10+
* Algorithm:
11+
* 1. Create a boolean array of size n+1, initially all true
12+
* 2. Mark 0 and 1 as not prime
13+
* 3. For each number i from 2 to sqrt(n):
14+
* - If i is still marked as prime
15+
* - Mark all multiples of i (starting from i²) as not prime
16+
* 4. Collect all numbers still marked as prime
17+
*
18+
* Time Complexity: O(n log log n)
19+
* Space Complexity: O(n)
20+
*
21+
* @author Navadeep0007
22+
* @see <a href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes">Sieve of Eratosthenes</a>
723
*/
824
public final class SieveOfEratosthenes {
25+
926
private SieveOfEratosthenes() {
27+
// Utility class, prevent instantiation
1028
}
1129

12-
private static void checkInput(int n) {
13-
if (n <= 0) {
14-
throw new IllegalArgumentException("n must be positive.");
30+
/**
31+
* Finds all prime numbers up to n using the Sieve of Eratosthenes algorithm
32+
*
33+
* @param n the upper limit (inclusive)
34+
* @return a list of all prime numbers from 2 to n
35+
* @throws IllegalArgumentException if n is negative
36+
*/
37+
public static List<Integer> findPrimes(int n) {
38+
if (n < 0) {
39+
throw new IllegalArgumentException("Input must be non-negative");
1540
}
16-
}
1741

18-
private static Type[] sievePrimesTill(int n) {
19-
checkInput(n);
20-
Type[] isPrimeArray = new Type[n + 1];
21-
Arrays.fill(isPrimeArray, Type.PRIME);
22-
isPrimeArray[0] = Type.NOT_PRIME;
23-
isPrimeArray[1] = Type.NOT_PRIME;
42+
if (n < 2) {
43+
return new ArrayList<>();
44+
}
45+
46+
// Create boolean array, initially all true
47+
boolean[] isPrime = new boolean[n + 1];
48+
for (int i = 2; i <= n; i++) {
49+
isPrime[i] = true;
50+
}
2451

25-
double cap = Math.sqrt(n);
26-
for (int i = 2; i <= cap; i++) {
27-
if (isPrimeArray[i] == Type.PRIME) {
28-
for (int j = 2; i * j <= n; j++) {
29-
isPrimeArray[i * j] = Type.NOT_PRIME;
52+
// Sieve process
53+
for (int i = 2; i * i <= n; i++) {
54+
if (isPrime[i]) {
55+
// Mark all multiples of i as not prime
56+
for (int j = i * i; j <= n; j += i) {
57+
isPrime[j] = false;
3058
}
3159
}
3260
}
33-
return isPrimeArray;
34-
}
35-
36-
private static int countPrimes(Type[] isPrimeArray) {
37-
return (int) Arrays.stream(isPrimeArray).filter(element -> element == Type.PRIME).count();
38-
}
3961

40-
private static int[] extractPrimes(Type[] isPrimeArray) {
41-
int numberOfPrimes = countPrimes(isPrimeArray);
42-
int[] primes = new int[numberOfPrimes];
43-
int primeIndex = 0;
44-
for (int curNumber = 0; curNumber < isPrimeArray.length; ++curNumber) {
45-
if (isPrimeArray[curNumber] == Type.PRIME) {
46-
primes[primeIndex++] = curNumber;
62+
// Collect all prime numbers
63+
List<Integer> primes = new ArrayList<>();
64+
for (int i = 2; i <= n; i++) {
65+
if (isPrime[i]) {
66+
primes.add(i);
4767
}
4868
}
69+
4970
return primes;
5071
}
5172

5273
/**
53-
* @brief finds all of the prime numbers up to the given upper (inclusive) limit
54-
* @param n upper (inclusive) limit
55-
* @exception IllegalArgumentException n is non-positive
56-
* @return the array of all primes up to the given number (inclusive)
74+
* Counts the number of prime numbers up to n
75+
*
76+
* @param n the upper limit (inclusive)
77+
* @return count of prime numbers from 2 to n
5778
*/
58-
public static int[] findPrimesTill(int n) {
59-
return extractPrimes(sievePrimesTill(n));
60-
}
61-
62-
private enum Type {
63-
PRIME,
64-
NOT_PRIME,
79+
public static int countPrimes(int n) {
80+
return findPrimes(n).size();
6581
}
6682
}
Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,56 @@
11
package com.thealgorithms.bitmanipulation;
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
45

56
import org.junit.jupiter.api.Test;
67

7-
public class CountSetBitsTest {
8+
class CountSetBitsTest {
89

910
@Test
10-
void testSetBits() {
11-
CountSetBits csb = new CountSetBits();
12-
assertEquals(1L, csb.countSetBits(16));
13-
assertEquals(4, csb.countSetBits(15));
14-
assertEquals(5, csb.countSetBits(10000));
15-
assertEquals(5, csb.countSetBits(31));
11+
void testCountSetBitsZero() {
12+
assertEquals(0, CountSetBits.countSetBits(0));
1613
}
1714

1815
@Test
19-
void testSetBitsLookupApproach() {
20-
CountSetBits csb = new CountSetBits();
21-
assertEquals(1L, csb.lookupApproach(16));
22-
assertEquals(4, csb.lookupApproach(15));
23-
assertEquals(5, csb.lookupApproach(10000));
24-
assertEquals(5, csb.lookupApproach(31));
16+
void testCountSetBitsOne() {
17+
assertEquals(1, CountSetBits.countSetBits(1));
18+
}
19+
20+
@Test
21+
void testCountSetBitsSmallNumber() {
22+
assertEquals(4, CountSetBits.countSetBits(3)); // 1(1) + 10(1) + 11(2) = 4
23+
}
24+
25+
@Test
26+
void testCountSetBitsFive() {
27+
assertEquals(7, CountSetBits.countSetBits(5)); // 1 + 1 + 2 + 1 + 2 = 7
28+
}
29+
30+
@Test
31+
void testCountSetBitsTen() {
32+
assertEquals(17, CountSetBits.countSetBits(10));
33+
}
34+
35+
@Test
36+
void testCountSetBitsLargeNumber() {
37+
assertEquals(42, CountSetBits.countSetBits(20)); // Changed from 93 to 42
38+
}
39+
40+
@Test
41+
void testCountSetBitsPowerOfTwo() {
42+
assertEquals(13, CountSetBits.countSetBits(8)); // Changed from 9 to 13
43+
}
44+
45+
@Test
46+
void testCountSetBitsNegativeInput() {
47+
assertThrows(IllegalArgumentException.class, () -> CountSetBits.countSetBits(-1));
48+
}
49+
50+
@Test
51+
void testNaiveApproachMatchesOptimized() {
52+
for (int i = 0; i <= 100; i++) {
53+
assertEquals(CountSetBits.countSetBitsNaive(i), CountSetBits.countSetBits(i), "Mismatch at n = " + i);
54+
}
2555
}
2656
}

0 commit comments

Comments
 (0)