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 <= 9
za wymagający zmniejszenia. Dlatego singleDigit(8)
będzie miał count = 0
i 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 <= 9
nawet 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ć, .reduce
ponieważ 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.log
przyspieszył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.log
wypychanie wyników do tablicy i używanie .length
dla count
jest 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 .reduce
uż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.log
z 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. ;-)