Jeśli próbujesz po prostu policzyć, ile razy się zmniejsza, i nie przejmujesz się konkretnie rekurencją ... możesz po prostu usunąć rekurencję. Poniższy kod pozostaje wierny oryginalnemu wpisowi, ponieważ nie jest uważany num <= 9za wymagający zmniejszenia. Dlatego singleDigit(8)będzie miał count = 0i singleDigit(39)będzie miał count = 3, podobnie jak PO i zaakceptowana odpowiedź pokazują:
const singleDigit = (num) => {
let count = 0, ret, x;
while (num > 9) {
ret = 1;
while (num > 9) {
x = num % 10;
num = (num - x) / 10;
ret *= x;
}
num *= ret;
count++;
console.log(num);
}
console.log("Answer = " + num + ", count = " + count);
return num;
}
Przetwarzanie liczb 9 lub mniejszych (tj. num <= 9) Nie jest konieczne . Niestety kod OP będzie przetwarzany, num <= 9nawet jeśli go nie liczy. Powyższy kod w ogóle nie będzie przetwarzany ani liczony num <= 9. Po prostu mi to przekazuje.
Zdecydowałem się nie używać, .reduceponieważ wykonanie faktycznej matematyki było znacznie szybsze do wykonania. I dla mnie łatwiejsze do zrozumienia.
Dalsze myślenie o prędkości
Uważam, że dobry kod jest również szybki. Jeśli używasz tego typu redukcji (która jest często używana w numerologii), być może będziesz musiał użyć go na ogromnej ilości danych. W takim przypadku prędkość będzie najważniejsza.
Używanie obu .map(Number)i console.log(na każdym etapie redukcji) jest bardzo długie do wykonania i niepotrzebne. Samo usunięcie .map(Number)z PO przyspieszyło go o około 4,38x. Usunięcie console.logprzyspieszyło tak bardzo, że prawie niemożliwe było prawidłowe przetestowanie (nie chciałem na to czekać).
Tak więc, podobnie jak odpowiedź customcommandera , nieużywanie .map(Number)ani nie console.logwypychanie wyników do tablicy i używanie .lengthdla countjest znacznie szybsze. Niestety dla customcommander „s odpowiedź, stosując funkcję generatora jest naprawdę bardzo powolny (które odpowiedź jest około 2.68x wolniej niż OP bez .map(Number)i console.log)
Zamiast tego .reduceużyłem właśnie faktycznej matematyki. Już ta pojedyncza zmiana przyspieszyła moją wersję funkcji o współczynnik 3,59x.
Wreszcie rekurencja jest wolniejsza, zajmuje miejsce na stosie, zużywa więcej pamięci i ma limit liczby powtórzeń. Lub, w tym przypadku, ile kroków redukcji można użyć, aby zakończyć pełną redukcję. Wdrożenie rekurencji w pętle iteracyjne utrzymuje to wszystko w tym samym miejscu na stosie i nie ma teoretycznego limitu liczby kroków redukcji, których można użyć do ukończenia. W związku z tym funkcje te mogą tutaj „zmniejszyć” liczbę całkowitą o dowolnej wielkości, ograniczoną jedynie czasem wykonania i długością tablicy.
Wszystko to na uwadze ...
const singleDigit2 = (num) => {
let red, x, arr = [];
do {
red = 1;
while (num > 9) {
x = num % 10;
num = (num - x) / 10;
red *= x;
}
num *= red;
arr.push(num);
} while (num > 9);
return arr;
}
let ans = singleDigit2(39);
console.log("singleDigit2(39) = [" + ans + "], count = " + ans.length );
// Output: singleDigit2(39) = [27,14,4], count = 3
Powyższa funkcja działa bardzo szybko. Jest to około 3.13x szybszy niż OP (bez .map(Number)i console.log) i około 8.4x szybszy niż customcommander „s odpowiedzi. Należy pamiętać, że usunięcie console.logz PO uniemożliwia wygenerowanie liczby na każdym etapie redukcji. Stąd potrzeba tutaj wypchnięcia tych wyników do tablicy.
PT
.map(Number)jest zbędny, ponieważ*operator i tak zmusza wartości do numerowania. ;-)