|
| 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