Skip to content

Commit f7d376d

Browse files
committed
feat: add findLongestRecurringCycle algorithm
1 parent ff314a2 commit f7d376d

File tree

3 files changed

+103
-2
lines changed

3 files changed

+103
-2
lines changed

Diff for: Maths/MobiusFunction.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ export const mobiusFunction = (number) => {
2828
return primeFactorsArray.length !== new Set(primeFactorsArray).size
2929
? 0
3030
: primeFactorsArray.length % 2 === 0
31-
? 1
32-
: -1
31+
? 1
32+
: -1
3333
}

Diff for: Project-Euler/Problem026.js

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* Problem - Longest Recurring Cycle
3+
*
4+
* @see {@link https://projecteuler.net/problem=26}
5+
*
6+
* Find the value of denominator < 1000 for which 1/denominator contains the longest recurring cycle in its decimal fraction part.
7+
*
8+
* A unit fraction (1/denominator) either terminates or repeats. We need to determine the length of the repeating sequence (cycle)
9+
* for each fraction where the denominator is between 2 and 999, and find the denominator that produces the longest cycle.
10+
*/
11+
12+
/**
13+
* Main function to find the denominator < limit with the longest recurring cycle in 1/denominator.
14+
*
15+
* @param {number} limit - The upper limit for the denominator (exclusive).
16+
* @returns {number} The denominator that has the longest recurring cycle in its decimal fraction part.
17+
*/
18+
function findLongestRecurringCycle(limit) {
19+
/**
20+
* Calculates the length of the recurring cycle for 1 divided by a given denominator.
21+
*
22+
* @param {number} denominator - The denominator of the unit fraction (1/denominator).
23+
* @returns {number} The length of the recurring cycle in the decimal part of 1/denominator.
24+
*/
25+
function getRecurringCycleLength(denominator) {
26+
// A map to store the position of each remainder encountered during division
27+
const remainderPositions = new Map()
28+
let numerator = 1 // We start with 1 as the numerator (as we're computing 1/denominator)
29+
let position = 0 // This tracks the position of each digit in the decimal sequence
30+
31+
// Continue until the remainder becomes 0 (terminating decimal) or a cycle is found
32+
while (numerator !== 0) {
33+
// If the remainder has been seen before, we've found the start of the cycle
34+
if (remainderPositions.has(numerator)) {
35+
// The length of the cycle is the current position minus the position when the remainder first appeared
36+
return position - remainderPositions.get(numerator)
37+
}
38+
39+
// Record the position of this remainder
40+
remainderPositions.set(numerator, position)
41+
42+
// Multiply numerator by 10 to simulate long division and get the next digit
43+
numerator = (numerator * 10) % denominator
44+
position++ // Move to the next digit position
45+
}
46+
47+
// If numerator becomes 0, it means the decimal terminates (no cycle)
48+
return 0
49+
}
50+
51+
let maxCycleLength = 0 // Store the maximum cycle length found
52+
let denominatorWithMaxCycle = 0 // Store the denominator corresponding to the longest cycle
53+
54+
// Iterate through each possible denominator from 2 up to (limit - 1)
55+
for (let denominator = 2; denominator < limit; denominator++) {
56+
// Calculate the cycle length for the current denominator
57+
const cycleLength = getRecurringCycleLength(denominator)
58+
59+
// Update the maximum length and the corresponding denominator if a longer cycle is found
60+
if (cycleLength > maxCycleLength) {
61+
maxCycleLength = cycleLength
62+
denominatorWithMaxCycle = denominator
63+
}
64+
}
65+
66+
// Return the denominator that has the longest recurring cycle
67+
return denominatorWithMaxCycle
68+
}
69+
70+
// Exporting the main function for use in other modules
71+
export { findLongestRecurringCycle }

Diff for: Project-Euler/test/Problem026.test.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { findLongestRecurringCycle } from '../Problem026'
2+
3+
/**
4+
* Tests for the findLongestRecurringCycle function.
5+
*/
6+
describe('findLongestRecurringCycle', () => {
7+
// Test to check the basic case with a limit of 10
8+
test('should return 7 for limit of 10', () => {
9+
const result = findLongestRecurringCycle(10)
10+
expect(result).toBe(7)
11+
})
12+
13+
// Test to check with a limit of 1000
14+
test('should return the correct value for limit of 1000', () => {
15+
const result = findLongestRecurringCycle(1000)
16+
expect(result).toBe(983) // The expected result is the denominator with the longest cycle
17+
})
18+
19+
// Test with a smaller limit to validate behavior
20+
test('should return 3 for limit of 4', () => {
21+
const result = findLongestRecurringCycle(4)
22+
expect(result).toBe(3)
23+
})
24+
25+
// Test with a limit of 2, where there is no cycle
26+
test('should return 0 for limit of 2', () => {
27+
const result = findLongestRecurringCycle(2)
28+
expect(result).toBe(0) // No cycle for fractions 1/1 and 1/2
29+
})
30+
})

0 commit comments

Comments
 (0)