Skip to content

Commit 0a136de

Browse files
committed
Solved Codility CountSemiPrime problem.
1 parent 817ea3a commit 0a136de

12 files changed

+672
-4
lines changed

codility/11.sieve-of-eratosthenes/1.lesson/solution.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ import "fmt"
44

55
// Returns array of n numbers from 0.
66
// Index represents the number and
7-
// the value 1 means the index number is prime,
8-
// 0 means composite.
7+
// the value 0 means the index number is prime,
8+
// 1 means composite.
9+
10+
// The logic is to represent 0 for prime in contrast
11+
// to the tutorial.
12+
913
// This function implments sieve concept.
1014
func markPrime(n int) []int {
1115
sieve := make([]int, n+1)
@@ -35,6 +39,7 @@ func markPrime(n int) []int {
3539

3640
// Returns an integer array with index as numbers
3741
// and values representing the smallest prime factor.
42+
// This is the exact implementation as above sieve().
3843
func smallestPrimeFactors(n int) []int {
3944
F := make([]int, n+1)
4045
i := 2
@@ -65,6 +70,8 @@ func smallestPrimeFactors(n int) []int {
6570
func primeFactors(n int) []int {
6671
primeFactors := []int{}
6772

73+
n = 9
74+
6875
F := smallestPrimeFactors(n)
6976

7077
for F[n] > 0 {

codility/11.sieve-of-eratosthenes/1.lesson/solution_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func TestSmallestPrimeFactor(t *testing.T) {
3333
}
3434

3535
func TestPrimeFactor(t *testing.T) {
36-
for k, test := range primeFactor[1:] {
36+
for k, test := range primeFactor[:] {
3737
fmt.Printf("k %v | test %v\n", k, test.description)
3838

3939
if got := primeFactors(test.n); !reflect.DeepEqual(got, test.want) {

codility/11.sieve-of-eratosthenes/1.lesson/test_cases.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ var smallestPrimeFactor = []struct {
3232
want: []int{0, 0, 0, 0, 2, 0, 2, 0, 2, 3, 2, 0, 2, 0, 2, 3, 2, 0, 2, 0, 2, 3, 2, 0, 2, 5},
3333
err: "",
3434
},
35+
{
36+
description: "Smallest prime factors of 26 numbers.",
37+
n: 26,
38+
want: []int{0, 0, 0, 0, 2, 0, 2, 0, 2, 3, 2, 0, 2, 0, 2, 3, 2, 0, 2, 0, 2, 3, 2, 0, 2, 5},
39+
err: "",
40+
},
3541
}
3642

3743
var primeFactor = []struct {
@@ -49,7 +55,32 @@ var primeFactor = []struct {
4955
{
5056
description: "Prime factors of 25.",
5157
n: 25,
52-
want: []int{2, 2, 3},
58+
want: []int{5, 5},
59+
err: "",
60+
},
61+
{
62+
description: "Prime factors of 100.",
63+
n: 100,
64+
want: []int{2, 2, 5, 5},
65+
err: "",
66+
},
67+
68+
{
69+
description: "Prime factors of 100000.",
70+
n: 100000,
71+
want: []int{2, 2, 2, 2, 2, 5, 5, 5, 5, 5},
72+
err: "",
73+
},
74+
{
75+
description: "Prime factors of 26.",
76+
n: 26,
77+
want: []int{2, 13},
78+
err: "",
79+
},
80+
{
81+
description: "Prime factors of 16.",
82+
n: 16,
83+
want: []int{2, 2, 2, 2},
5384
err: "",
5485
},
5586
}
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
# Problem
2+
3+
https://app.codility.com/programmers/lessons/11-sieve_of_eratosthenes/count_semiprimes/
4+
5+
A prime is a positive integer X that has exactly two
6+
distinct divisors: 1 and X.
7+
The first few prime integers are 2, 3, 5, 7, 11 and 13.
8+
9+
A semiprime is a natural number that is
10+
**the product of two (not necessarily distinct) prime numbers.**
11+
12+
The first few semiprimes are 4, 6, 9, 10, 14, 15, 21, 22, 25, 26.
13+
14+
You are given two non-empty arrays P and Q, each consisting of M integers.
15+
These arrays represent queries about the number of semiprimes within specified ranges.
16+
17+
Query K requires you to **find the number of semiprimes**
18+
within the range (P[K], Q[K]), where 1 ≤ P[K] ≤ Q[K] ≤ N.
19+
20+
For example, consider an integer N = 26 and arrays P, Q such that:
21+
P[0] = 1 Q[0] = 26
22+
P[1] = 4 Q[1] = 10
23+
P[2] = 16 Q[2] = 20
24+
25+
The number of semiprimes within each of these ranges is as follows:
26+
(1, 26) is 10,
27+
(4, 10) is 4,
28+
(16, 20) is 0.
29+
30+
Write a function: func Solution(N int, P []int, Q []int) []int
31+
32+
that, given an integer N and two non-empty arrays P and Q
33+
consisting of M integers, returns an array consisting of
34+
M elements specifying the consecutive answers to all the
35+
queries.
36+
37+
38+
For example, given an integer N = 26 and arrays P, Q such that:
39+
P[0] = 1 Q[0] = 26
40+
P[1] = 4 Q[1] = 10
41+
P[2] = 16 Q[2] = 20
42+
43+
the function should return the values [10, 4, 0], as explained above.
44+
45+
46+
Write an efficient algorithm for the following assumptions:
47+
N is an integer within the range [1..50,000];
48+
M is an integer within the range [1..30,000];
49+
each element of arrays P, Q is an integer within the range [1..N];
50+
P[i] ≤ Q[i].
51+
52+
53+
# Solution
54+
### Analysis
55+
56+
**Semiprime: The product of two prime numbers.**
57+
58+
(1, 26) is 10 :
59+
1
60+
2
61+
3
62+
4 2*2
63+
5
64+
6 2*3
65+
7
66+
8
67+
9 3*3
68+
10 2*5
69+
11
70+
12
71+
13
72+
14 2*7
73+
15 3*5
74+
16
75+
17
76+
18
77+
19
78+
20
79+
21 3*7
80+
22 2*11
81+
23
82+
24
83+
25 5*5
84+
26 2*13
85+
86+
(4, 10) is 4
87+
4 2*2
88+
5
89+
6 2*3
90+
7
91+
8
92+
9 3*3
93+
10 2*5
94+
95+
(16, 20) is 0
96+
16 2*2*2*2
97+
17 1*17
98+
18 2*3*3
99+
19 1*19
100+
20 2*2*5
101+
102+
103+
From the lessons activities, primeFactors() returns
104+
the number of smallets prime numbers, we can just
105+
count them. If 2 primes, increase semiprime.
106+
107+
### Pseudo count
108+
Get the smallest prime numbers till N
109+
110+
Count the smallest prime numbers of all N
111+
112+
Count mark if the number is semiprime for all N
113+
114+
For each range, count the semi prime numbers in that range.
115+
This logic can be improved counting the semi primes while counting
116+
the semiprimes for all N but for now we do it the naive way.
117+
118+
119+
The improved logic is using prefix sum.
120+
But it gave wrong count for 4,10 = 3
121+
122+
(1, 26) is 10
123+
(4, 10) is 4
124+
(16, 20) is 0
125+
126+
(13, 20) is 2
127+
128+
129+
(23, 29) is 2
130+
131+
When even include both ends, no substraction
132+
When odd, substract max-min
133+
134+
135+
### First solution
136+
Scores:
137+
Task Score 44%
138+
Correctness 50%
139+
Performance 40%
140+
141+
It failed small functional tests.
142+
143+
Failed small random:
144+
WRONG ANSWER, got [17, 17, 16, 15, 10] expected [17, 17, 16, 15, 7]
145+
146+
147+
### Second solution
148+
149+
Checking solution based on the test cases.
150+
> Min Prime Factor 60:
151+
0 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
152+
0 0 0 0 2 0 2 0 2 3 2 0 2 0 2 3 2 0 2 0 2 3 2 0 2 5 2 3 2 0 2 0 2 3 2 5 2 0 2
153+
154+
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
155+
3 2 0 2 0 2 3 2 0 2 7 2 3 2 0 2 5 2 3 2 0 2
156+
157+
158+
> Prefix Sum 40:
159+
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
160+
0 0 0 1 1 2 2 2 3 4 4 4 4 5 6 6 6 6 6 6 7 8 8 8 9 10 10 10 10 10 10 10 11 12 13 13 13 14
161+
162+
39 40
163+
15 15
164+
165+
166+
> Prefix sum 60:
167+
0 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
168+
0 0 0 0 1 1 2 2 2 3 4 4 4 4 5 6 6 6 6 6 6 7 8 8 8 9 10 10 10 10 10 10 10 11 12 13 13 13 14
169+
0 0 0 0 0 1 1 0 0 1 1
170+
1 1 1 1 1 1 1 1 1 1 1 1
171+
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
172+
15 15 15 15 15 15 15 16 16 16 17 17 18 18 18 18 19 19 20 21 21 21
173+
1 1 1 1 1 1 1 1
174+
175+
(16, 27) 27-16 = 11(is Odd, max-min); 10 - 6 = 4; Verification: Correct
176+
177+
(10, 30) 20(even, include both ends, take max); PS[30] = 10; Verification: Wrong
178+
PS[30]=10, PS[10]=4; Even if we do PS[30-10] = 6
179+
Prime Factors: 10, 13, 14, 15, 19, 20, 21 ; count = 7
180+
Hence, the code logic had to be changed for even
181+
`semiPrimes[i] = (prefixSumSemiPrime[max]`
182+
to
183+
`semiPrimes[i] = (prefixSumSemiPrime[max] - prefixSumSemiPrime[min]) + 1`
184+
185+
(8,31) 23 Odd, so max-min; 10-2 = 8; Verification: Correct
186+
PFac: 9 10 14 15 21 22 25 26, count = 8
187+
188+
(15,18) 3 odd, max-min = 6-6 = 0; Verification: Wrong
189+
PFac: 15, count = 1.
190+
In this case we might have to check if there was change from 14 to 15.
191+
```
192+
semiPrimes[i] = prefixSumSemiPrime[max] - prefixSumSemiPrime[min]
193+
to
194+
semiPrimes[i] = prefixSumSemiPrime[max] - prefixSumSemiPrime[min-1]
195+
```
196+
197+
Gives same result 44.
198+
The minor change flipped correctness of the previous result.
199+
extreme_four fails, while small function pass, while
200+
small_functional still fails.
201+
202+
Performace tests gives same result
203+
204+
### Third submission
205+
Even making the the minor changes for odd case (15,18) did not make
206+
any difference to the score. It remaided as second.
207+
208+
### Fourth submission
209+
Scores: Task Score 55% Correctness 75% Performance 40%
210+
211+
There was an issue when the smallest number was less than 4.
212+
This caused an increase of 1 because the prime counts for
213+
numbers less than 4 are 0. Resolved the issue with a check
214+
if the number was less than 4.
215+
```go
216+
else if (max-min)%2 == 0 {
217+
218+
if prefixSumSemiPrime[max] == prefixSumSemiPrime[min] {
219+
semiPrimes[i] = 0
220+
221+
} else {
222+
223+
if min < 4 {
224+
semiPrimes[i] = prefixSumSemiPrime[max]
225+
226+
} else {
227+
228+
semiPrimes[i] = (prefixSumSemiPrime[max] - prefixSumSemiPrime[min]) + 1
229+
}
230+
}
231+
232+
}
233+
```
234+
235+
There are still failing cases:
236+
WRONG ANSWER,
237+
got [8, 13, __11__, 12, 9, 13, 8, 11,..
238+
expected [8, 13, __10__, 12, 9, 13, 8, 11,..
239+
240+
WRONG ANSWER,
241+
got [__49__, __51__, 46, 21, 42, 2..
242+
expected [__48__, __50__, 46, 21, 42, 2..
243+
244+
WRONG ANSWER,
245+
got ..565, 6429, 6666, __1806__, 4139, __2416__, __6002__,..
246+
expected ..565, 6429, 6666, __1805__, 4139, __2415__, __6001__,..
247+
248+
WRONG ANSWER,
249+
got ..955, 9085, 9244, `9878`, `10147`, 7624, 1062..
250+
expected ..955, 9085, 9244, `9877`, `10146`, 7624, 1062..
251+
252+
From the failing case analysis, there is just an increase of a number
253+
in what is expected.
254+
255+
Checked it by adding similar condition for odd case
256+
but it did not change the results.
257+
```go
258+
if min < 4 {
259+
semiPrimes[i] = prefixSumSemiPrime[max]
260+
261+
} else {
262+
semiPrimes[i] = prefixSumSemiPrime[max] - prefixSumSemiPrime[min-1]
263+
}
264+
```
265+
266+
To fix the issue, the problem was to find the
267+
test cases. As the lowest range was in 40, it
268+
helped a lot to find that case.
269+
270+
(24, 30) previously was giving 3 semi prime count
271+
which should have been 2. The issue was prefix sum
272+
of semi prime included a value that change by previous
273+
semiprime number.
274+
Index : 22 23 24 25 26 27 28 28 30
275+
SuffixSum of Semipeime numbers: 8 8 8 9 10 10 10 10 10
276+
277+
24 is not a semiprime number but in the suffix sum
278+
is included which is incorrect. So the check was made
279+
if there it really was a semiprime which is done by
280+
comparing if previous number is lower than it. i.e,
281+
the number to be semiprime, it has to be one more than
282+
the previous. Here 23 also has 8, so 24 is not semiprime,
283+
hence it should not be included in the total number of
284+
semiprimes in that range.
285+
```go
286+
if prefixSumSemiPrime[min] > prefixSumSemiPrime[min-1] {
287+
semiPrimes[i] = (prefixSumSemiPrime[max] - prefixSumSemiPrime[min]) + 1
288+
289+
} else {
290+
semiPrimes[i] = (prefixSumSemiPrime[max] - prefixSumSemiPrime[min])
291+
}
292+
```
293+
294+
This solution scored 100.
295+
296+
The code coverage from the test is also 100 percent.
297+
298+
There are alot of conditions which I believe can be improved.

0 commit comments

Comments
 (0)