Problema FizzBuzz este o problema tipica pe care multi candidati la interviurile din industria IT au primit-o spre rezolvare. Este o problema simpla, dar in cele mai multe cazuri problemele simple sunt foarte dificile pentru unii candidati.

Ea reprezinta un algoritm important care poate foarte bine testa abilitatile de dezvoltator ale candidatului la postul de web developer.

Acesta poate rezolva problema in orice limbaj de programare este dispus sa lucreze.

Ceea ce poate observa cel care intervieveaza candidatul este:

  • felul in care intelege problema;
  • stilul de programare abordat;
  • complexitatea algoritmului redactat;
  • scalabilitatea algoritmului si eficienta sa.

 

FizzBuzz poate fi enuntata astfel:

Se dau numerele de la 1 la 100. Sa se afiseze numerele de la 1-100 in urmatorul fel:
  • Numerele multiplu de 3 trebuie inlocuite cu textul „Fizz”.
  • Numerele multiplu de 5 trebuie inlocuite cu textul „Buzz”.
  • Numerele multiplu de 3 si 5 trebuie inlocuite cu textul „FizzBuzz”.

Vom incerca rezolvarea acestei probleme folosind JavaScript.

Pare un algoritm simplu care ar trebui sa afiseze la rulare un sir de genul:

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz ...

Primul algoritm pe care il scriu majoritatea candidatilor este algoritmul clasic.

Primul pas

Problema incepe prin a tipari pe ecran primele 100 de numere.

fizzbuzz1
Fizzbuzz

Daca rulam vom obtine primele 100 de numere.

Sa discutam putin despre declararea variabilei „i”. In felul in care a fost declarata aici ea este o variabila globala folosita in functie. De obicei, o variabila folosita intr-o functie trebuie sa ramana locala in functie.

Functiile isi construiesc variable locale. Ele nu trebuie sa fie disponibile global. Dupa incheierea rularii functiei, variabilele locale trebuie dealocate si nu mai trebuie sa fie disponibile.

FizzBuzz
FizzBuzz

Deci mi se afiseaza 101 la sfarsit – exact valoarea cu care i paraseste bucla. Pentru ca variabila „i” sa devina locala in functie, putem proceda astfel:

FizzBuzz
FizzBuzz

 

Este normal! Apelarea la final a lui „i” imi aduce o eroare. Imi raporteaza ca nu cunoaste simbolul „i” pe care incerc sa il tiparesc in linia 7 pozitia 13 din cod. Putem elimina aceasta apelare din codul nostru.

Al doilea pas

Pasul urmator in construirea solutiei problemei initiale este ca functia sa inlocuiasca valoarea multiplilor lui 3 cu textul „Fizz”.

Pentru aceasta voi folosi o structura alternativa DACA_ATUNCI_ALTFEL in felul urmator.

FizzBuzz
FizzBuzz

Observam o linie finala in output care imi aduce „undefined”. Folosirea in codul sursa a unei functii care nu returneaza nimic, imi provoaca in output aceasta linie.

Functia poate returna la final un raspuns generic.

FizzBuzz
FizzBuzz

 

 

In regula! Daca si aceasta problema s-a rezolvat putem trece la pasul urmator.

Al treilea pas

Multiplii lui 5 din sirul tiparit pe ecran sa fie inlocuiti cu cuvantul „Buzz”. Adica in loc de 5, 10, 15, …. sa apara cuvantul „Buzz”.

FizzBuzz
FizzBuzz

 

Gata! Am rezolvat si aceasta problema!

Ultimul pas

Ultimul pas ar fi ca in locul multiplilor de 3 si de 5 sa punem cuvantul „FizzBuzz”. Putem reduce afisarea valorilor pana suntem in faza de dezvoltare a programului. Cerem afisarea numerelor pana la 20.

Mergand in virtutea inertiei, majoritatea candidatilor rezolva astfel problema:

FizzBuzz
FizzBuzz

 

Nu am obtinut un rezultat bun! 15 este de exemplu divizibil si cu 3 si cu 5, deci el trebuie inlocuit cu „FizzBuzz”. Candidatul se poate bloca aici si nu poate sa isi explice ce s-a intamplat?

Cand folosesc in cod mai multe instructiuni IF_ELSE care se indeplinesc in anumite conditii trebuie sa respect o logica corecta. Trebuie sa ma duc de la cele mai specifice la cele mai putin specifice.

In cazul nostru, deoarece se indeplinea prima conditie in cazul lui 15 care este divizibil cu 3, nu mai intra in ultimul IF. Se afiseaza „Fizz” nu „FizzBuzz” cum ma asteptam.

Remediem si aceasta problema:

 

FizzBuzz
FizzBuzz

Gata! S-a rezolvat.

Sa vedem mai departe cum poate fi optimizat acest program.

Optimizarea presupune scrierea unei solutii viabile în cazul problemei date. Scopul final este de a selectarea din multimea de solutiilor propuse pe aceea care este cea mai avantajoasa.
Optimizarea inseamna un ansamblu de metode si tehnici care determina gasirea si alegerea unei solutii optime pentru un algoritm.
Din punct de vedere matematic, optimizarea se poate face prin cercetarea operationala, programare liniara, programare dinamica, algoritmi genetici etc.

O prima optimizare

Putem trece toata logica pe un singur numar. Pentru tot sirul de valori, apelam de mai multe ori logica pentru un numar.
FizzBuzz
FizzBuzz
Am scris o functie separata pentru un singur numar careia i-am spus „uniqueNr”. Functia „fizzBuzz” apeleaza functia „uniqueNr” pentru fiecare valoare i din sirul de valori de la 1..100. Algoritmul functioneaza corect.
Inca avem structuri de decizie multiple si structuri repetitive.

O a doua optimizare

Ar putea consta in eliminarea unor instructiuni „console.log” si obligarea algoritmului sa returneze un raspuns.
FizzBuzz
FizzBuzz

Optimizare mai puternica

Ar fi util sa reducem functia „toUniqueNr”, adica sa o scriem mai compacta. Calculam un „index” intr-o variabila cu acelasi nume care poate lua valorile:

  • 1 daca gaseste un numar multiplu de 3 (number %3 ==0)
  • 2 daca gaseste un numar multiplu de 5 (number %5 ==0)
  • 1+2 = 3 daca gaseste un numar multiplu de 3 si 5 (number %3 ==0 && number%5==0).

De asemenea, raspunsul ii cerem sa il dea intr-un vector de raspunsuri care va contine numai i la index 0 si 3 elemente la index 1, 2 si 3:

let responses = [i, "Fizz","Buzz","FizzBuzz"];

In acest fel, putem elimina structurile IF si intregul cod devine mult mai compact.
FizzBuzz
FizzBuzz

Codul functioneaza in continuare!

Mai pot reduce codul prin eliminarea:

  • variabilei „index” si inlocuirea ei cu expresia completa (number % 3 == 0 ? 1 : 0) + (number % 5 == 0 ? 2 : 0)
  • variabilei „responses”.

Codul ar putea arata cam asa:

FizzBuzz
FizzBuzz

In final, eliminam si functia „toUniqueNr”. Mutam raspunsul returnat de ea in interiorul instructiunii „console.log” din functia „fizzbuzz(n)”.

Atentie insa! Trebuie inlocuita variabia „number” cu variabila „i” pentru ca in functia „fizzbuzz(n)” nu avem varaiabila „number” definita.

FizzBuzz
FizzBuzz

Asa arata aceasta problema simpla rezolvata complet si optim.

Algoritmii folositi in pasii intermediari nu sunt unici. Exista si alte metode prin care putem scrie codul.

Ne-am propus sa „surprindem” evolutia codului de la o forma bruta catre aceasta forma finala foarte compacta.

In concluzie

Excelent zic eu! Ce stim acum?

Candidatul care rezolva asa problema intelege cu adevarat cum se scrie un cod optimizat si ce inseamna scalabilitate, mentenabilitate, modularitate, testare, eficienta.

Candidatul a primit o problema relativ simpla, dar a stiut sa il duca pe cel care il asculta, pe carari fine si clare catre un rezultat optimizat.

In mod normal, majoritatea programatorilor se opresc atunci cand codul functioneaza corect si returneaza solutia pe care au obtinut-o prima data.

Un programator care poate scrie un astfel de cod merita intreaga consideratie!

 

Succes si voua sa reusiti!

 

 

Lasă un răspuns