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;
+}
```