Tökéletes szám tesztelő (Újratervezés Program, kompetenciateszt gyakorlás)

Tegnap feladtam egy feladatot a (Újratervezés Program Tanuló Szoba) Facebook-csoportban:

Adott egy szám (pl. textfield-ben), mondjuk meg róla, hogy tökéletes szám-e. (pl. írjuk ki a konzolra, hogy az-e vagy sem).
Tökéletes szám egy nemnegatív egész szám, ha a önmagánál kisebb osztóinak összege önmaga. (Pl. 6 = 1 + 2 + 3).
(Kevés ilyen szám van, ezért az egyik megoldás az lehetne, hogy ha szám == az első_tökéletes_szám_a_wikipédián VAGY szám == a második_tökéletes_szám_a_wikipédián… akkor igen… keress rá más megoldást!)

Mi a megoldás?

Induljunk ki a tökéletes szám definíciójából, és vizsgáljuk meg ezt a tulajdonságot. Ahhoz, hogy el tudjuk dönteni, hogy egyenlő-e a számmal a magánál kisebb osztók összege, előbb meg kell határozni a magánál kisebb osztók összegét. Az összeghez pedig az osztókat.

Egy szám magánál kisebb osztóinak meghatározása

Végigmegyünk az osztók számára lehetséges tartományon egy for-ciklussal, és megnézzük, hogy a a ciklusváltozó osztja-e az eredeti számot.
Mi számít lehetséges tartománynak? Ha nagyon egyszerűen akarod elintézni, akkor [1..n-1], de ezt még lehet szűkíteni, hiszen a szám felénél nagyobb (számnál kisebb) osztó nincs, tehát lehet ez a felső határ: [1…n/2]. (Ha még ügyesebb vagy, akkor megoldod úgy, hogy a szám négyzetgyökéig vizsgálódjunk, mégis benne legyen az összes lehetséges osztó, de maradjunk egyelőre a feléig történő vizsgálatnál).

let szam = ...;
for(let oszto = 1; oszto <= szam / 2; oszto++) {
   if (szam % oszto == 0) {
      console.log(oszto);
   }
}

Ez eddig az alapalgoritmusok közül a kiválogatás algoritmusa. Kiválogatjuk azokat az értékeket, amelyek osztják a számot.
De ezzel még nem végeztünk.

Egy szám magánál kisebb osztói összegének meghatározása

Adjuk őket össze!
Alkalmazzuk az összegzés algoritmusát. Mit összegzünk? Azokat az "oszto" értékeket, amelyekre igaz az, hogy osztják a számot.

let szam = ...;
let osszeg = 0;
for(let oszto = 1; oszto <= szam / 2; oszto++) {
   if (szam % oszto == 0) {
      osszeg = osszeg + oszto;
      //console.log(oszto);
   }
}
console.log(osszeg);

Az új részeknek köszönhetően most már megvan az összege a magánál kisebb osztóknak.

Feltétel vizsgálata

Hasonlítsuk össze a megkapott összeget az eredeti számmal:

let szam = ...;
let osszeg = 0;
for(let oszto = 1; oszto <= szam / 2; oszto++) {
   if (szam % oszto == 0) {
      osszeg = osszeg + oszto;
      //console.log(oszto);
   }
}
if (osszeg == szam) {
   console.log("A " + szam + " tökéletes.");
} else {
   console.log("A " + szam + " nem tökéletes.");
}

(Ha tovább akarsz menni, akkor persze lehetséges háromoperandusú operátorral (?: ) is kezelni ezt a kiírást).

Tömbbel?

Lehet, hogy eszedbe jutott az, hogy tömbbel oldd meg a feladatot: a kiválogatást egy tömbbe végzed, majd annak a tömbnek az elemeit összegzed. Véleményem szerint takarítsuk meg a memóriát, és inkább "röptében" összegezzük a számokat, azaz akkor, amikor előálltak. A tömbös megoldást nem javaslom.

Más megoldás?

Persze, simán elképzelhető más, matematikai alapú megoldás is, amivel a kompetenciádat még jobban bizonyítod, de azt gondolom, ha ezt most érted, esetleg te is így csináltad, az már egy jó pont.

Felépítés

Amit érdemes a konkrét megoldáson túl ebből a gondolkodásmódból elsajátítani, az a program lebontásának (analízis) és részekből való összeépítésének képessége.

Továbblépés

Ha szeretnél hasonló feladatokat megoldani, automatikus feladatértékelővel, és esetleg mentori segítséget is kapni hozzá, akkor

Sikeres felkészülést kívánok!
Pasztuhov Dániel