Categories
coding solutions

Codility: count_semiprimes Solution

Task

A prime is a positive integer X that has exactly two distinct divisors: 1 and X. The first few prime integers are 2, 3, 5, 7, 11 and 13.

A semiprime is a natural number that is the product of two (not necessarily distinct) prime numbers. The first few semiprimes are 4, 6, 9, 10, 14, 15, 21, 22, 25, 26.

You are given two non-empty arrays P and Q, each consisting of M integers. These arrays represent queries about the number of semiprimes within specified ranges.

Query K requires you to find the number of semiprimes within the range (P[K], Q[K]), where 1 ≤ P[K] ≤ Q[K] ≤ N.

Write a function:vector<int> solution(int N, vector<int> &P, vector<int> &Q);

that, given an integer N and two non-empty arrays P and Q consisting of M integers, returns an array consisting of M elements specifying the consecutive answers to all the queries.

Write an efficient algorithm for the following assumptions:

  • N is an integer within the range [1..50,000];
  • M is an integer within the range [1..30,000];
  • each element of arrays P, Q is an integer within the range [1..N];
  • P[i] ≤ Q[i].

Solution

The form of the query suggest using a sequence of partial sums, as in previous exercises.
The prime numbers can be calculated using the sieve of Eratosthenes. Note the following optimisations:
  • We only need to search for factors up to the square root of N, as the smallest factor will be less than or equal to this.
  • When updating the sieve with a new potential factor, we can start from the square of that factor as smaller multiples will be found already
#include <cassert> #include <math.h> #include <vector> vector<int> solution(int N, vector<int> &P, vector<int> &Q) { vector<int> result(P.size()); // array of smallest factor of numbers int factors[N + 1]; for (int fact = 0; fact <= N; fact++) { factors[fact] = 0; } // only need to go up to sq root as smallest factor will be <= sq root of number int largest = ceil(sqrt(N)); for (int fact = 2; fact <= largest; fact++) { // unfound factors only if (factors[fact] == 0) { // can start from sq of factor as smallest factors of values less than that will already be found int mult = fact * fact; while (mult <= N) { if (factors[mult] == 0) { // found smallest factor factors[mult] = fact; } mult += fact; } } } // for // partSums = partial sum of number of semiprimes int partSums[N + 1]; partSums[0] = partSums[1] = 0; int countSemi = 0; // count of number of semiprimes found so far for (int fact = 2; fact <= N; fact++) { int nextFact = factors[fact]; if (nextFact != 0) { // not prime if (factors[nextFact] == 0) { // smallest factor is prime, what about other nextFact = fact / nextFact; if (factors[nextFact] == 0) { countSemi++; } } } partSums[fact] = countSemi; } // now do result for (ulong expr = 0; expr < P.size(); expr++) { result[expr] = partSums[Q[expr]] – partSums[P[expr] – 1]; } return result; }

Notes

I noticed the following problems with this:
  • The check at line 21 is not needed because you don’t have to store the smallest factor, any factor will do
  • The check at line 37 is redundant because all the factors stored are prime

Test Function

This code tests the solution

void check(int N, vector<int> P, vector<int> Q, const vector<int> expected) { vector<int> res = solution(N, P, Q); assert(expected.size() == res.size()); for (ulong i = 0; i < res.size(); i++) { assert(expected[i] == res[i]); } } int main() { check(26, {1, 4, 16}, {26, 10, 20}, {10, 4, 0}); check(1, {1}, {1}, {0}); check(4, {1, 2, 3, 4, 1, 2, 3, 1, 2, 1}, {4, 4, 4, 4, 3, 3, 3, 2, 2, 1}, {1, 1, 1, 1, 0, 0, 0, 0, 0, 0}); check(50, {1, 2, 3, 4, 10}, {50, 49, 48, 40, 30}, {17, 17, 16, 15, 7}); }

Results

Codility Results

Correctness100%
Performance100%
Time Complexity O(N * log(log(N)) + M)

Other Solutions

These are some other solutions to this problem on the internet
These generally use an array of booleans to flag whether each number is prime, and then populate the semiprimes in a separate loop.

Index of solutions to Codility Lessons in C++

Leave a Reply

Your email address will not be published. Required fields are marked *