From f7d376d2e60b500ad7bf7103cab3f2c6ff57f336 Mon Sep 17 00:00:00 2001 From: Lamine Gaye Date: Wed, 16 Oct 2024 15:09:36 +0000 Subject: [PATCH 1/7] feat: add findLongestRecurringCycle algorithm --- Maths/MobiusFunction.js | 4 +- Project-Euler/Problem026.js | 71 +++++++++++++++++++++++++++ Project-Euler/test/Problem026.test.js | 30 +++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 Project-Euler/Problem026.js create mode 100644 Project-Euler/test/Problem026.test.js diff --git a/Maths/MobiusFunction.js b/Maths/MobiusFunction.js index bd268b8bbd..4239d6ab31 100644 --- a/Maths/MobiusFunction.js +++ b/Maths/MobiusFunction.js @@ -28,6 +28,6 @@ export const mobiusFunction = (number) => { return primeFactorsArray.length !== new Set(primeFactorsArray).size ? 0 : primeFactorsArray.length % 2 === 0 - ? 1 - : -1 + ? 1 + : -1 } diff --git a/Project-Euler/Problem026.js b/Project-Euler/Problem026.js new file mode 100644 index 0000000000..edee6f2299 --- /dev/null +++ b/Project-Euler/Problem026.js @@ -0,0 +1,71 @@ +/** + * Problem - Longest Recurring Cycle + * + * @see {@link https://projecteuler.net/problem=26} + * + * Find the value of denominator < 1000 for which 1/denominator contains the longest recurring cycle in its decimal fraction part. + * + * A unit fraction (1/denominator) either terminates or repeats. We need to determine the length of the repeating sequence (cycle) + * for each fraction where the denominator is between 2 and 999, and find the denominator that produces the longest cycle. + */ + +/** + * Main function to find the denominator < limit with the longest recurring cycle in 1/denominator. + * + * @param {number} limit - The upper limit for the denominator (exclusive). + * @returns {number} The denominator that has the longest recurring cycle in its decimal fraction part. + */ +function findLongestRecurringCycle(limit) { + /** + * Calculates the length of the recurring cycle for 1 divided by a given denominator. + * + * @param {number} denominator - The denominator of the unit fraction (1/denominator). + * @returns {number} The length of the recurring cycle in the decimal part of 1/denominator. + */ + function getRecurringCycleLength(denominator) { + // A map to store the position of each remainder encountered during division + const remainderPositions = new Map() + let numerator = 1 // We start with 1 as the numerator (as we're computing 1/denominator) + let position = 0 // This tracks the position of each digit in the decimal sequence + + // Continue until the remainder becomes 0 (terminating decimal) or a cycle is found + while (numerator !== 0) { + // If the remainder has been seen before, we've found the start of the cycle + if (remainderPositions.has(numerator)) { + // The length of the cycle is the current position minus the position when the remainder first appeared + return position - remainderPositions.get(numerator) + } + + // Record the position of this remainder + remainderPositions.set(numerator, position) + + // Multiply numerator by 10 to simulate long division and get the next digit + numerator = (numerator * 10) % denominator + position++ // Move to the next digit position + } + + // If numerator becomes 0, it means the decimal terminates (no cycle) + return 0 + } + + let maxCycleLength = 0 // Store the maximum cycle length found + let denominatorWithMaxCycle = 0 // Store the denominator corresponding to the longest cycle + + // Iterate through each possible denominator from 2 up to (limit - 1) + for (let denominator = 2; denominator < limit; denominator++) { + // Calculate the cycle length for the current denominator + const cycleLength = getRecurringCycleLength(denominator) + + // Update the maximum length and the corresponding denominator if a longer cycle is found + if (cycleLength > maxCycleLength) { + maxCycleLength = cycleLength + denominatorWithMaxCycle = denominator + } + } + + // Return the denominator that has the longest recurring cycle + return denominatorWithMaxCycle +} + +// Exporting the main function for use in other modules +export { findLongestRecurringCycle } diff --git a/Project-Euler/test/Problem026.test.js b/Project-Euler/test/Problem026.test.js new file mode 100644 index 0000000000..ac276bf748 --- /dev/null +++ b/Project-Euler/test/Problem026.test.js @@ -0,0 +1,30 @@ +import { findLongestRecurringCycle } from '../Problem026' + +/** + * Tests for the findLongestRecurringCycle function. + */ +describe('findLongestRecurringCycle', () => { + // Test to check the basic case with a limit of 10 + test('should return 7 for limit of 10', () => { + const result = findLongestRecurringCycle(10) + expect(result).toBe(7) + }) + + // Test to check with a limit of 1000 + test('should return the correct value for limit of 1000', () => { + const result = findLongestRecurringCycle(1000) + expect(result).toBe(983) // The expected result is the denominator with the longest cycle + }) + + // Test with a smaller limit to validate behavior + test('should return 3 for limit of 4', () => { + const result = findLongestRecurringCycle(4) + expect(result).toBe(3) + }) + + // Test with a limit of 2, where there is no cycle + test('should return 0 for limit of 2', () => { + const result = findLongestRecurringCycle(2) + expect(result).toBe(0) // No cycle for fractions 1/1 and 1/2 + }) +}) From 2b739bfced6cd28c4dbdafeb5c24981c162f8f1a Mon Sep 17 00:00:00 2001 From: Lamine Gaye Date: Wed, 16 Oct 2024 15:28:49 +0000 Subject: [PATCH 2/7] fix: format MobiusFunction.js with Prettier --- Maths/MobiusFunction.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Maths/MobiusFunction.js b/Maths/MobiusFunction.js index 4239d6ab31..bd268b8bbd 100644 --- a/Maths/MobiusFunction.js +++ b/Maths/MobiusFunction.js @@ -28,6 +28,6 @@ export const mobiusFunction = (number) => { return primeFactorsArray.length !== new Set(primeFactorsArray).size ? 0 : primeFactorsArray.length % 2 === 0 - ? 1 - : -1 + ? 1 + : -1 } From fd1d6e6d5a6d861854d37ff057237e91b4242c59 Mon Sep 17 00:00:00 2001 From: Lamine Gaye Date: Wed, 16 Oct 2024 17:58:15 +0000 Subject: [PATCH 3/7] Add Problem 027 - Quadratic Primes algorithm and tests --- Project-Euler/Problem027.js | 61 +++++++++++++++++++++++++++ Project-Euler/test/Problem027.test.js | 9 ++++ 2 files changed, 70 insertions(+) create mode 100644 Project-Euler/Problem027.js create mode 100644 Project-Euler/test/Problem027.test.js diff --git a/Project-Euler/Problem027.js b/Project-Euler/Problem027.js new file mode 100644 index 0000000000..dac47a4552 --- /dev/null +++ b/Project-Euler/Problem027.js @@ -0,0 +1,61 @@ +/** + * Problem - Quadratic Primes + * + * @see {@link https://projecteuler.net/problem=27} + * + * The quadratic expression n^2 + an + b, where |a| < 1000 and |b| ≤ 1000, + * produces a positive prime for consecutive values of n, starting with n = 0. + * Find the product of the coefficients, a and b, for the quadratic expression that + * produces the maximum number of primes for consecutive values of n. + */ + +/** + * Main function to find the coefficients a and b that produce the maximum number + * of consecutive primes for the quadratic expression n^2 + an + b. + * + * @returns {{maxPrimes: number, product: number}} An object containing the maximum number of primes + * and the product of coefficients a and b. + */ +function findMaxConsecutivePrimes() { + /** + * Checks if a number is prime. + * + * @param {number} n - The number to check for primality. + * @returns {boolean} True if n is a prime number, false otherwise. + */ + function isPrime(n) { + if (n < 2) return false // 0 and 1 are not prime numbers + if (n === 2) return true // 2 is a prime number + if (n % 2 === 0) return false // Exclude even numbers + for (let i = 3; i <= Math.sqrt(n); i += 2) { + // Check odd divisors only + if (n % i === 0) return false // Divisible by i, so not prime + } + return true // No divisors found, so it is prime + } + + let maxPrimes = 0 // Store the maximum number of primes found + let product = 0 // Store the product of coefficients a and b + + for (let a = -999; a < 1000; a++) { + for (let b = -1000; b <= 1000; b++) { + let n = 0 + let consecutivePrimes = 0 + while (true) { + const result = n * n + a * n + b // Evaluate the quadratic expression + if (result < 0 || !isPrime(result)) break // Stop if the result is negative or not prime + consecutivePrimes++ + n++ + } + if (consecutivePrimes > maxPrimes) { + maxPrimes = consecutivePrimes + product = a * b // Calculate product of coefficients a and b + } + } + } + + return { maxPrimes, product } // Return the results +} + +// Exporting the main function for use in other modules +export { findMaxConsecutivePrimes } diff --git a/Project-Euler/test/Problem027.test.js b/Project-Euler/test/Problem027.test.js new file mode 100644 index 0000000000..f7859f03d6 --- /dev/null +++ b/Project-Euler/test/Problem027.test.js @@ -0,0 +1,9 @@ +import { findMaxConsecutivePrimes } from '../Problem027' + +describe('Problem 027 - Quadratic Primes', () => { + test('should return the correct product of coefficients for max consecutive primes', () => { + const { maxPrimes, product } = findMaxConsecutivePrimes() + expect(maxPrimes).toBe(71) + expect(product).toBe(-59231) + }) +}) From c6192d760d9d097352d49ccb49a76dd189309927 Mon Sep 17 00:00:00 2001 From: Lamine Gaye Date: Sun, 20 Oct 2024 19:34:56 +0000 Subject: [PATCH 4/7] feat: add findLongestRecurringCycle algorithm (Problem 26) --- Project-Euler/Problem026.js | 25 +++++----------------- Project-Euler/test/Problem026.test.js | 30 +++++++-------------------- 2 files changed, 13 insertions(+), 42 deletions(-) diff --git a/Project-Euler/Problem026.js b/Project-Euler/Problem026.js index edee6f2299..684f1c55a1 100644 --- a/Project-Euler/Problem026.js +++ b/Project-Euler/Problem026.js @@ -4,9 +4,6 @@ * @see {@link https://projecteuler.net/problem=26} * * Find the value of denominator < 1000 for which 1/denominator contains the longest recurring cycle in its decimal fraction part. - * - * A unit fraction (1/denominator) either terminates or repeats. We need to determine the length of the repeating sequence (cycle) - * for each fraction where the denominator is between 2 and 999, and find the denominator that produces the longest cycle. */ /** @@ -23,49 +20,37 @@ function findLongestRecurringCycle(limit) { * @returns {number} The length of the recurring cycle in the decimal part of 1/denominator. */ function getRecurringCycleLength(denominator) { - // A map to store the position of each remainder encountered during division const remainderPositions = new Map() - let numerator = 1 // We start with 1 as the numerator (as we're computing 1/denominator) - let position = 0 // This tracks the position of each digit in the decimal sequence + let numerator = 1 + let position = 0 - // Continue until the remainder becomes 0 (terminating decimal) or a cycle is found while (numerator !== 0) { - // If the remainder has been seen before, we've found the start of the cycle if (remainderPositions.has(numerator)) { - // The length of the cycle is the current position minus the position when the remainder first appeared return position - remainderPositions.get(numerator) } - // Record the position of this remainder remainderPositions.set(numerator, position) - // Multiply numerator by 10 to simulate long division and get the next digit numerator = (numerator * 10) % denominator - position++ // Move to the next digit position + position++ } - // If numerator becomes 0, it means the decimal terminates (no cycle) return 0 } - let maxCycleLength = 0 // Store the maximum cycle length found - let denominatorWithMaxCycle = 0 // Store the denominator corresponding to the longest cycle + let maxCycleLength = 0 + let denominatorWithMaxCycle = 0 - // Iterate through each possible denominator from 2 up to (limit - 1) for (let denominator = 2; denominator < limit; denominator++) { - // Calculate the cycle length for the current denominator const cycleLength = getRecurringCycleLength(denominator) - // Update the maximum length and the corresponding denominator if a longer cycle is found if (cycleLength > maxCycleLength) { maxCycleLength = cycleLength denominatorWithMaxCycle = denominator } } - // Return the denominator that has the longest recurring cycle return denominatorWithMaxCycle } -// Exporting the main function for use in other modules export { findLongestRecurringCycle } diff --git a/Project-Euler/test/Problem026.test.js b/Project-Euler/test/Problem026.test.js index ac276bf748..67f60c2b48 100644 --- a/Project-Euler/test/Problem026.test.js +++ b/Project-Euler/test/Problem026.test.js @@ -4,27 +4,13 @@ import { findLongestRecurringCycle } from '../Problem026' * Tests for the findLongestRecurringCycle function. */ describe('findLongestRecurringCycle', () => { - // Test to check the basic case with a limit of 10 - test('should return 7 for limit of 10', () => { - const result = findLongestRecurringCycle(10) - expect(result).toBe(7) - }) - - // Test to check with a limit of 1000 - test('should return the correct value for limit of 1000', () => { - const result = findLongestRecurringCycle(1000) - expect(result).toBe(983) // The expected result is the denominator with the longest cycle - }) - - // Test with a smaller limit to validate behavior - test('should return 3 for limit of 4', () => { - const result = findLongestRecurringCycle(4) - expect(result).toBe(3) - }) - - // Test with a limit of 2, where there is no cycle - test('should return 0 for limit of 2', () => { - const result = findLongestRecurringCycle(2) - expect(result).toBe(0) // No cycle for fractions 1/1 and 1/2 + it.each([ + { limit: 10, expected: 7 }, + { limit: 1000, expected: 983 }, // The denominator with the longest cycle for limit of 1000 + { limit: 4, expected: 3 }, + { limit: 2, expected: 0 } // No cycle for fractions 1/1 and 1/2 + ])('should return $expected for limit of $limit', ({ limit, expected }) => { + const result = findLongestRecurringCycle(limit) + expect(result).toBe(expected) }) }) From 714bdab27863e2589cc7acb91ac633bc4cf19f37 Mon Sep 17 00:00:00 2001 From: Lamine Gaye Date: Sun, 20 Oct 2024 19:54:51 +0000 Subject: [PATCH 5/7] feat: add Quadratic Primes algorithm and tests (Problem 27) --- Project-Euler/Problem027.js | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/Project-Euler/Problem027.js b/Project-Euler/Problem027.js index dac47a4552..d1d27aa3b2 100644 --- a/Project-Euler/Problem027.js +++ b/Project-Euler/Problem027.js @@ -17,45 +17,35 @@ * and the product of coefficients a and b. */ function findMaxConsecutivePrimes() { - /** - * Checks if a number is prime. - * - * @param {number} n - The number to check for primality. - * @returns {boolean} True if n is a prime number, false otherwise. - */ function isPrime(n) { - if (n < 2) return false // 0 and 1 are not prime numbers - if (n === 2) return true // 2 is a prime number - if (n % 2 === 0) return false // Exclude even numbers + if (n < 2) return false + if (n === 2) return true + if (n % 2 === 0) return false for (let i = 3; i <= Math.sqrt(n); i += 2) { - // Check odd divisors only - if (n % i === 0) return false // Divisible by i, so not prime + if (n % i === 0) return false } - return true // No divisors found, so it is prime + return true } - let maxPrimes = 0 // Store the maximum number of primes found - let product = 0 // Store the product of coefficients a and b + let maxPrimes = 0 + let product = 0 for (let a = -999; a < 1000; a++) { for (let b = -1000; b <= 1000; b++) { let n = 0 - let consecutivePrimes = 0 while (true) { - const result = n * n + a * n + b // Evaluate the quadratic expression - if (result < 0 || !isPrime(result)) break // Stop if the result is negative or not prime - consecutivePrimes++ + const result = n * n + a * n + b + if (result < 0 || !isPrime(result)) break n++ } - if (consecutivePrimes > maxPrimes) { - maxPrimes = consecutivePrimes - product = a * b // Calculate product of coefficients a and b + if (n > maxPrimes) { + maxPrimes = n + product = a * b } } } - return { maxPrimes, product } // Return the results + return { maxPrimes, product } } -// Exporting the main function for use in other modules export { findMaxConsecutivePrimes } From fbe4fb4a82d3a445dcea2753a4c1cc66552b0445 Mon Sep 17 00:00:00 2001 From: Lamine Gaye Date: Mon, 21 Oct 2024 06:55:51 +0000 Subject: [PATCH 6/7] Add countDistinctPowers function and associated tests --- Project-Euler/Problem029.js | 39 +++++++++++++++++++++++++++ Project-Euler/test/Problem029.test.js | 20 ++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 Project-Euler/Problem029.js create mode 100644 Project-Euler/test/Problem029.test.js diff --git a/Project-Euler/Problem029.js b/Project-Euler/Problem029.js new file mode 100644 index 0000000000..f24da79dd6 --- /dev/null +++ b/Project-Euler/Problem029.js @@ -0,0 +1,39 @@ +/** + * Problem - Distinct Powers + * + * Find the number of distinct terms generated by a^b for 2 ≤ a ≤ 100 and 2 ≤ b ≤ 100. + */ + +/** + * Main function to count distinct powers a^b. + * + * @param {number} minA + * @param {number} maxA + * @param {number} minB + * @param {number} maxB + * @returns {number} + */ +function countDistinctPowers(minA, maxA, minB, maxB) { + /** + * Set to store distinct terms generated by a^b. + */ + const distinctTerms = new Set() + + for (let a = minA; a <= maxA; a++) { + for (let b = minB; b <= maxB; b++) { + distinctTerms.add(Math.pow(a, b)) + } + } + + return distinctTerms.size +} + +const minA = 2 +const maxA = 100 +const minB = 2 +const maxB = 100 + +const result = countDistinctPowers(minA, maxA, minB, maxB) +console.log(`Number of distinct terms: ${result}`) + +export { countDistinctPowers } diff --git a/Project-Euler/test/Problem029.test.js b/Project-Euler/test/Problem029.test.js new file mode 100644 index 0000000000..428ce1813d --- /dev/null +++ b/Project-Euler/test/Problem029.test.js @@ -0,0 +1,20 @@ +import { countDistinctPowers } from '../Problem029' + +/** + * Tests for the countDistinctPowers function. + */ +describe('countDistinctPowers', () => { + it.each([ + { minA: 2, maxA: 5, minB: 2, maxB: 5, expected: 15 }, + { minA: 2, maxA: 100, minB: 2, maxB: 100, expected: 9183 }, + { minA: 2, maxA: 2, minB: 2, maxB: 2, expected: 1 }, + { minA: 3, maxA: 3, minB: 2, maxB: 5, expected: 4 }, + { minA: 10, maxA: 10, minB: 2, maxB: 5, expected: 4 } + ])( + 'should return $expected for ranges $minA to $maxA and $minB to $maxB', + ({ minA, maxA, minB, maxB, expected }) => { + const result = countDistinctPowers(minA, maxA, minB, maxB) + expect(result).toBe(expected) + } + ) +}) From 02360d3ccacb249227a3c40e037e16cbdc610ad5 Mon Sep 17 00:00:00 2001 From: Lamine Gaye Date: Mon, 21 Oct 2024 07:31:24 +0000 Subject: [PATCH 7/7] Add countDistinctPowers function and associated tests --- Project-Euler/Problem030.js | 33 +++++++++++++++++++++++++++ Project-Euler/test/Problem030.test.js | 8 +++++++ 2 files changed, 41 insertions(+) create mode 100644 Project-Euler/Problem030.js create mode 100644 Project-Euler/test/Problem030.test.js diff --git a/Project-Euler/Problem030.js b/Project-Euler/Problem030.js new file mode 100644 index 0000000000..d53aba8097 --- /dev/null +++ b/Project-Euler/Problem030.js @@ -0,0 +1,33 @@ +/** + * Problem - Sum of Fifth Powers of Digits + * + * Find the sum of all the numbers that can be written as the sum of fifth powers of their digits. + * + * @see {@link https://projecteuler.net/problem=30} + */ + +/** + * Main function to calculate the sum of all numbers that can be expressed + * as the sum of the fifth powers of their digits. + * + * @returns {number} The sum of all numbers that can be written as the sum of fifth powers of their digits. + */ +function sumOfFifthPowers() { + const fifthPowers = Array.from({ length: 10 }, (_, i) => i ** 5) + const results = [] + + for (let num = 10; num < 354295; num++) { + const sumOfDigits = num + .toString() + .split('') + .reduce((sum, digit) => sum + fifthPowers[digit], 0) + + if (sumOfDigits === num) { + results.push(num) + } + } + + return results.reduce((acc, curr) => acc + curr, 0) +} + +export { sumOfFifthPowers } diff --git a/Project-Euler/test/Problem030.test.js b/Project-Euler/test/Problem030.test.js new file mode 100644 index 0000000000..bc0ac30e36 --- /dev/null +++ b/Project-Euler/test/Problem030.test.js @@ -0,0 +1,8 @@ +import { sumOfFifthPowers } from '../Problem030' // Adjust the path if necessary + +describe('sumOfFifthPowers', () => { + it('should return the sum of all numbers that can be written as the sum of fifth powers of their digits', () => { + const result = sumOfFifthPowers() + expect(result).toBe(443839) // Expected result based on the problem statement + }) +})