From e9f8f425b3fdcf5b313e0d5d938af9734bef985f Mon Sep 17 00:00:00 2001 From: gikf <60067306+gikf@users.noreply.github.com> Date: Fri, 14 May 2021 08:18:22 +0200 Subject: [PATCH] fix(curriculum): rework Project Euler 74 (#42057) * fix: rework challenge to use argument in function * fix: add solution * fix: use MathJax for consistent look --- .../problem-74-digit-factorial-chains.md | 104 ++++++++++++++---- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/curriculum/challenges/english/10-coding-interview-prep/project-euler/problem-74-digit-factorial-chains.md b/curriculum/challenges/english/10-coding-interview-prep/project-euler/problem-74-digit-factorial-chains.md index c1eeeda4d7..f8645892aa 100644 --- a/curriculum/challenges/english/10-coding-interview-prep/project-euler/problem-74-digit-factorial-chains.md +++ b/curriculum/challenges/english/10-coding-interview-prep/project-euler/problem-74-digit-factorial-chains.md @@ -10,39 +10,58 @@ dashedName: problem-74-digit-factorial-chains The number 145 is well known for the property that the sum of the factorial of its digits is equal to 145: -
1! + 4! + 5! = 1 + 24 + 120 = 145
+$$1! + 4! + 5! = 1 + 24 + 120 = 145$$ Perhaps less well known is 169, in that it produces the longest chain of numbers that link back to 169; it turns out that there are only three such loops that exist: -
- 169 → 363601 → 1454 → 169
- 871 → 45361 → 871
- 872 → 45362 → 872
-
+$$\begin{align} +&169 → 363601 → 1454 → 169\\\\ +&871 → 45361 → 871\\\\ +&872 → 45362 → 872\\\\ +\end{align}$$ + It is not difficult to prove that EVERY starting number will eventually get stuck in a loop. For example, -
- 69 → 363600 → 1454 → 169 → 363601 (→ 1454)
- 78 → 45360 → 871 → 45361 (→ 871)
- 540 → 145 (→ 145)
-
+$$\begin{align} +&69 → 363600 → 1454 → 169 → 363601\\ (→ 1454)\\\\ +&78 → 45360 → 871 → 45361\\ (→ 871)\\\\ +&540 → 145\\ (→ 145)\\\\ +\end{align}$$ Starting with 69 produces a chain of five non-repeating terms, but the longest non-repeating chain with a starting number below one million is sixty terms. -How many chains, with a starting number below one million, contain exactly sixty non-repeating terms? +How many chains, with a starting number below `n`, contain exactly sixty non-repeating terms? # --hints-- -`digitFactorialChains()` should return a number. +`digitFactorialChains(2000)` should return a number. ```js -assert(typeof digitFactorialChains() === 'number'); +assert(typeof digitFactorialChains(2000) === 'number'); ``` -`digitFactorialChains()` should return 402. +`digitFactorialChains(2000)` should return `6`. ```js -assert.strictEqual(digitFactorialChains(), 402); +assert.strictEqual(digitFactorialChains(2000), 6); +``` + +`digitFactorialChains(100000)` should return `42`. + +```js +assert.strictEqual(digitFactorialChains(100000), 42); +``` + +`digitFactorialChains(500000)` should return `282`. + +```js +assert.strictEqual(digitFactorialChains(500000), 282); +``` + +`digitFactorialChains(1000000)` should return `402`. + +```js +assert.strictEqual(digitFactorialChains(1000000), 402); ``` # --seed-- @@ -50,16 +69,63 @@ assert.strictEqual(digitFactorialChains(), 402); ## --seed-contents-- ```js -function digitFactorialChains() { +function digitFactorialChains(n) { return true; } -digitFactorialChains(); +digitFactorialChains(2000); ``` # --solutions-- ```js -// solution required +function digitFactorialChains(n) { + function sumDigitsFactorials(number) { + let sum = 0; + while (number > 0) { + sum += factorials[number % 10]; + number = Math.floor(number / 10); + } + return sum; + } + + const factorials = [1]; + for (let i = 1; i < 10; i++) { + factorials.push(factorials[factorials.length - 1] * i); + } + + const sequences = { + 169: 3, + 871: 2, + 872: 2, + 1454: 3, + 45362: 2, + 45461: 2, + 3693601: 3 + }; + let result = 0; + + for (let i = 2; i < n; i++) { + let curNum = i; + let chainLength = 0; + const curSequence = []; + while (curSequence.indexOf(curNum) === -1) { + curSequence.push(curNum); + curNum = sumDigitsFactorials(curNum); + chainLength++; + if (sequences.hasOwnProperty(curNum) > 0) { + chainLength += sequences[curNum]; + break; + } + } + if (chainLength === 60) { + result++; + } + for (let j = 1; j < curSequence.length; j++) { + sequences[curSequence[j]] = chainLength - j; + } + } + return result; +} ```