CountSemiprimes – Codility – Solution

Java solution to Codility CountSemiprimes problem (Lesson 11 – Sieve of Eratosthenes) which scored 55%. The problem is to count the semiprime numbers in the given range [a..b].

The strategy is similar to the Primes Demo problem.

References

Solution to Count-Semiprimes (Code Says)

How to convert List<Integer> to int[] in Java (Stack Overflow)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.codility.lesson11.sieveoferatosthenes;

import java.util.ArrayList;
import java.util.List;

public class CountSemiprimes {
  public int[] solution(int N, int[] P, int[] Q) {
    //make size N+1 so will have direct mapping from array index
    boolean [] arePrimes = new boolean[N+1];

    arePrimes[0] = false; //0 is never prime
    arePrimes[1] = false; //1 is never prime
    for(int i=2; i<arePrimes.length; i++) {
      arePrimes[i] = true;
    }

    int nSquareRoot = (int) Math.sqrt(N);
    for(int i=2; i<=nSquareRoot; i++) {
      if(arePrimes[i]) {
        //start checking from i^2 because lower numbers will have already been checked
        //keep checking very multiple of i
        for(int j=i*i; j<=N; j+=i) {
          arePrimes[j] = false;
        }
      }
    }

    List primesList = new ArrayList();
    for(int i=2; i<arePrimes.length; i++) { if(arePrimes[i]) { primesList.add(i); } } //https://stackoverflow.com/questions/960431/how-to-convert-listinteger-to-int-in-java int[] primes = primesList.stream().mapToInt(i->i).toArray();

    int [] semiPrimes = new int[N + 1];

    //populate semi primes set in order
    //reference: https://codesays.com/2014/solution-to-count-semiprimes-by-codility/
    for(int i=0; i<primes.length-1; i++) { if(primes[i] * primes[i] > N) {
        continue;
      }
      semiPrimes[primes[i]*primes[i]] = 1;  //square of the prime
      for(int j=i+1; j<primes.length; j++) { if(primes[i] * primes[j] > N) {
          break; //semi primes are larger than N so can stop calculating them
        }
        semiPrimes[primes[i]*primes[j]] = 1;
      }
    }
   
    for(int i=1; i<semiPrimes.length; i++) {
      semiPrimes[i] += semiPrimes[i-1];
    }
   
    int [] results = new int[P.length];
    for(int i=0; i<P.length; i++) {
      results[i] = semiPrimes[Q[i]] - semiPrimes[P[i] - 1];
    }
    return results;
  }
}

TestNG test cases for this problem which all passed:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package test.com.codility.lesson11.sieveoferatosthenes;

import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import com.codility.lesson11.sieveoferatosthenes.CountSemiprimes;

public class CountSemiprimesTests {
  private CountSemiprimes solution;
 
  @BeforeTest
  public void setUp() {
    solution = new CountSemiprimes();
  }

  @DataProvider(name = "test1")
  public Object [][] createData1() {
    return new Object [][] {
      new Object [] { 26, new int [] { 1, 4, 16 }, new int [] { 26, 10, 20 }, new int [] { 10, 4, 0 } },
    };
  }

  @Test(dataProvider = "test1")
  public void verifySolution(int pInt, int [] pP, int [] pQ, int [] pExpected) {     
    int [] actual = solution.solution(pInt, pP, pQ);   
    Assert.assertEquals(actual.length, pExpected.length);  
    for(int i=0; i<actual.length; i++) {   
      Assert.assertEquals(actual[i], pExpected[i]);
    }  
  }
}