From 0ebad86104aededeeed69eaf416c552a130d69e7 Mon Sep 17 00:00:00 2001 From: Loosetooth Date: Sun, 2 Feb 2025 18:50:09 +0100 Subject: [PATCH] add kata --- 5kyu/k-primes/description.md | 25 +++++++++ 5kyu/k-primes/solution.ts | 106 +++++++++++++++++++++++++++++++++++ 5kyu/k-primes/tests.ts | 21 +++++++ 3 files changed, 152 insertions(+) create mode 100644 5kyu/k-primes/description.md create mode 100644 5kyu/k-primes/solution.ts create mode 100644 5kyu/k-primes/tests.ts diff --git a/5kyu/k-primes/description.md b/5kyu/k-primes/description.md new file mode 100644 index 0000000..055ae5f --- /dev/null +++ b/5kyu/k-primes/description.md @@ -0,0 +1,25 @@ +A natural number is called k-prime if it has exactly k prime factors, counted with multiplicity. For example: + +k = 2 --> 4, 6, 9, 10, 14, 15, 21, 22, ... +k = 3 --> 8, 12, 18, 20, 27, 28, 30, ... +k = 5 --> 32, 48, 72, 80, 108, 112, ... +A natural number is thus prime if and only if it is 1-prime. + +Task: +Complete the function count_Kprimes (or countKprimes, count-K-primes, kPrimes) which is given parameters k, start, end (or nd) and returns an array (or a list or a string depending on the language - see "Solution" and "Sample Tests") of the k-primes between start (inclusive) and end (inclusive). + +Example: +countKprimes(5, 500, 600) --> [500, 520, 552, 567, 588, 592, 594] +Notes: + +The first function would have been better named: findKprimes or kPrimes :-) +In C some helper functions are given (see declarations in 'Solution'). +For Go: nil slice is expected when there are no k-primes between start and end. +Second Task: puzzle (not for Shell) +Given a positive integer s, find the total number of solutions of the equation a + b + c = s, where a is 1-prime, b is 3-prime, and c is 7-prime. + +Call this function puzzle(s). + +Examples: +puzzle(138) --> 1 because [2 + 8 + 128] is the only solution +puzzle(143) --> 2 because [3 + 12 + 128] and [7 + 8 + 128] are the solutions diff --git a/5kyu/k-primes/solution.ts b/5kyu/k-primes/solution.ts new file mode 100644 index 0000000..f74bd0d --- /dev/null +++ b/5kyu/k-primes/solution.ts @@ -0,0 +1,106 @@ + +// sieve of eratosthenes +const primesBelow = (n: number): number[] => { + const primes: number[] = []; + const isPrime: boolean[] = Array(n).fill(true); + isPrime[0] = false; + isPrime[1] = false; + for (let i = 2; i < n; i++) { + if (isPrime[i]) { + primes.push(i); + for (let j = i * i; j < n; j += i) { + isPrime[j] = false; + } + } + } + + return primes; +} + +// prime factorization using trial division +const primeFactors = (n: number, primesList: number[]): number[] => { + const factors: number[] = []; + const sqrtN = Math.sqrt(n); + const primes = [...primesList]; + let currPrime = primes.shift() as number; + while (currPrime <= sqrtN) { + if (n % currPrime === 0) { + factors.push(currPrime); + n /= currPrime; + } else { + currPrime = primes.shift() as number; + } + } + + if (n > 1) { + factors.push(n); + } + + return factors; +} + +const generatePrimeFactors = (upper: number): number[] => { + // this stores the number of times a number is marked as a prime factor + const factors: number[] = Array(upper + 1).fill(0); + + for (let p = 2; p <= upper; p++) { + if (factors[p] === 0) { + // p is prime + // mark all multiples of p + for (let j = p; j <= upper; j += p) { + // also mark all multiples of p^2, p^3, ... + for(let k = j; k <= upper; k *= p) { + factors[k]++; + } + } + } + } + + return factors; +} + +// create static class which can be called a single time for a very large range +export class KPrimes { + private static limit = 10001000; + private static primeFactors = generatePrimeFactors(KPrimes.limit); + + public static countKprimes(k: number, start: number, nd: number): number[] { + if(nd > KPrimes.limit) { + throw new Error(`nd: ${nd} is greater than the limit: ${KPrimes.limit}`); + } + // filter out the numbers that have k prime factors + const result = []; + for (let i = start; i <= nd; i++) { + if (KPrimes.primeFactors[i] === k) { + result.push(i); + } + } + + return result; + } +} + +// using modified sieve of eratosthenes +export const countKprimes = (k: number, start: number, nd: number): number[] => { + return KPrimes.countKprimes(k, start, nd); +} + +export const puzzle = (s: number): number => { + const onePrimes = countKprimes(1, 0, s); + const threePrimes = countKprimes(3, 0, s); + const sevenPrimes = countKprimes(7, 0, s); + + let count = 0; + + onePrimes.forEach(onePrime => { + threePrimes.forEach(threePrime => { + sevenPrimes.forEach(sevenPrime => { + if (onePrime + threePrime + sevenPrime === s) { + count++; + } + }); + }); + }); + + return count; +} \ No newline at end of file diff --git a/5kyu/k-primes/tests.ts b/5kyu/k-primes/tests.ts new file mode 100644 index 0000000..67569cf --- /dev/null +++ b/5kyu/k-primes/tests.ts @@ -0,0 +1,21 @@ +import { countKprimes, puzzle } from './solution' +import { assert, config } from "chai"; +config.truncateThreshold = 0 + +function testing(actual: number | number[], expected: number | number[]) { + assert.deepEqual(actual, expected); +} + +describe("Fixed Tests", function () { + it("Basic tests countKprimes", function () { + testing(countKprimes(2, 0, 100), [4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49, 51, 55, 57, 58, 62, 65, 69, 74, 77, 82, 85, 86, 87, 91, 93, 94, 95]); + testing(countKprimes(3, 0, 100), [8, 12, 18, 20, 27, 28, 30, 42, 44, 45, 50, 52, 63, 66, 68, 70, 75, 76, 78, 92, 98, 99]); + testing(countKprimes(5, 1000, 1100), [1020, 1026, 1032, 1044, 1050, 1053, 1064, 1072, 1092, 1100]); + testing(countKprimes(5, 500, 600), [500, 520, 552, 567, 588, 592, 594]); + }); + + it("Basic tests puzzle", function () { + testing(puzzle(138), 1); + testing(puzzle(143), 2); + }); +}); \ No newline at end of file