Kolejne ciekawe ćwiczenie rekurencyjne – piszemy program, który liczy ilość cyfr 0 w liczbie. Do dzieła.
Pierwsze rozwiązanie:
function countZeros(num){
if(num === 0)
return 0;
let lastDigit = num % 10;
if(lastDigit === 0)
return 1 + countZeros(Math.floor(num / 10));
return 0 + countZeros(Math.floor(num / 10));
}
0 to base-case (czyli to, co zostanie po obcinaniu cyfr poprzez dzielenie bez reszty przez 10). Wyciąganie ostatniej liczby też chyba jest jasne, podobnie jak wywołanie rekurencyjne z 1 lub 0 + pomniejszona liczba.
Co najwyżej jeden edge-case się rysuje:
console.log(countZeros(10230010)); //4
console.log(countZeros(0)); //0
Pytanie jak do tego podchodzimy. Czy 0 ma 0 zer? W sensie 10 ma jedno ale w 10 to zero coś znaczy. Moim zdaniem ilość zer to ilość zer i trzeba to zrobić porządnie, ale tak, aby nie zepsuć base-case. Czyli:
function countZeros_v2(n){
if(n === 0)
return 1;
function _countZeros(num){
if(num === 0)
return 0;
let lastDigit = num % 10;
if(lastDigit === 0)
return 1 + _countZeros(Math.floor(num / 10));
return 0 + _countZeros(Math.floor(num / 10));
}
return _countZeros(n);
}
console.log(countZeros_v2(0)); //1
console.log(countZeros_v2(10)); //1
console.log(countZeros_v2(1000)); //3
I tak w przypadku 0 jako argumentu przekazanego bezpośrednio poprzez fasadę (czyli chcemy zwracać ilość 0 w zerze) zwracamy 1, zaś gdy funkcja sama siebie woła z 0 to (np. w 10 dodała że jest zero, podzieliła przez 10, 1 nie ma zera, podzieliła przez 10 i ma zero) to zwracamy 0 bo pora kończyć, już że 10 ma 1 mamy zapisane.