Invatare Atomica

Algoritmi simpli cu bucle

Progres lectie:
0%
🎯

Obiectivul lectiei

Vei invata sapte tipare de algoritmi care apar in aproape orice problema de informatica: acumulare (suma, produs), comparare (minim, maxim), numarare, gasirea divizorilor si verificarea daca un numar este prim. Toate folosesc o bucla care parcurge date si o variabila care „tine minte” un rezultat.

Dupa aceasta lectie vei putea:

  • Sa calculezi suma si produsul unui sir de numere folosind un acumulator
  • Sa determini minimul si maximul dintr-un sir printr-o singura parcurgere
  • Sa numeri cate elemente respecta o conditie (contor)
  • Sa afisezi divizorii unui numar si sa-i numeri
  • Sa verifici daca un numar este prim si sa explici de ce O(√n) este suficient
  • Sa indici complexitatea (notatia O) a fiecarui algoritm

Incearca singur!

Provocare:

Ai numerele 7, 2, 9, 4, 9, 1, 6. Fara sa scrii cod, descrie in cuvinte cum ai gasi cel mai mare numar parcurgandu-le o singura data, de la stanga la dreapta. Ce „tii minte” pe parcurs?

💡 Ai nevoie de un indiciu?

Tine minte o singura valoare: „cel mai mare vazut pana acum”. Incepe cu primul element. La fiecare element nou, daca e mai mare decat ce ai memorat, actualizeaza memoria.

Acest tipar — o variabila care retine un rezultat partial care se actualizeaza in bucla — este inima tuturor algoritmilor din aceasta lectie!

1

1. Suma cu acumulator

Un acumulator este o variabila in care „adunam” treptat un rezultat. Pentru suma il initializam cu 0 (elementul neutru al adunarii), apoi parcurgem numerele si la fiecare pas il marim.
# Suma numerelor de la 1 la n
n = 5
suma = 0
for i in range(1, n + 1):
    suma = suma + i
print("Suma de la 1 la", n, "este", suma)
Output real (rulat):
Suma de la 1 la 5 este 15
Complexitate: bucla face exact n pasi → O(n) (liniar).
2

2. Produsul (factorialul)

Pentru produs folosim acelasi tipar, dar initializam acumulatorul cu 1 (elementul neutru al inmultirii). Produsul numerelor de la 1 la n se numeste n factorial si se noteaza n!.
# Produsul numerelor de la 1 la n (factorialul lui n)
n = 5
produs = 1
for i in range(1, n + 1):
    produs = produs * i
print("Produsul (n!) pentru n =", n, "este", produs)
Output real (rulat):
Produsul (n!) pentru n = 5 este 120
5! = 1·2·3·4·5 = 120. Complexitate: O(n).
3

3. Minim si maxim dintr-un sir

Pentru minim si maxim „tinem minte” doi candidati. Ii pornim cu primul element (sigur exista in sir), apoi la fiecare element comparam si actualizam daca am gasit ceva mai mic / mai mare.
# Minimul si maximul dintr-un sir de numere
numere = [7, 2, 9, 4, 9, 1, 6]
minim = numere[0]
maxim = numere[0]
for x in numere:
    if x < minim:
        minim = x
    if x > maxim:
        maxim = x
print("Minim =", minim)
print("Maxim =", maxim)
Output real (rulat):
Minim = 1
Maxim = 9
O singura parcurgere → O(n). Initializarea cu primul element este mai sigura decat cu o „valoare mare” aleasa la noroc.
4

4. Numarare cu contor

Un contor este o variabila pornita de la 0 pe care o crestem cu 1 de fiecare data cand un element respecta o conditie. Aici numaram cate numere sunt pare (rest 0 la impartirea cu 2).
# Numararea elementelor pare dintr-un sir
numere = [7, 2, 9, 4, 9, 1, 6]
contor = 0
for x in numere:
    if x % 2 == 0:
        contor = contor + 1
print("Numar de elemente pare:", contor)
Output real (rulat):
Numar de elemente pare: 3
Elementele pare sunt 2, 4 si 6 → 3 elemente. Complexitate: O(n).
5

5. Divizorii unui numar

Un numar d este divizor al lui n daca n se imparte exact la d (rest 0). Ii cautam testand fiecare candidat de la 1 la n.
# Afisarea divizorilor lui n si numararea lor
n = 24
contor = 0
for d in range(1, n + 1):
    if n % d == 0:
        print(d, end=" ")
        contor = contor + 1
print()
print("Numar de divizori:", contor)
Output real (rulat):
1 2 3 4 6 8 12 24
Numar de divizori: 8
Aceasta varianta testeaza toti candidatii pana la n → O(n). Se poate accelera testand doar pana la √n (vezi atomul urmator).
6

6. Numar prim (test pana la √n)

Un numar prim este un numar natural mai mare ca 1 care are exact doi divizori: 1 si pe el insusi. Nu e nevoie sa testam toti candidatii pana la n: divizorii vin in perechi (d si n/d), iar cel mic din pereche este mereu ≤ √n. De aceea conditia d * d <= n este suficienta.
# Verificare daca un numar este prim (varianta simpla)
n = 29
if n < 2:
    prim = False
else:
    prim = True
    d = 2
    while d * d <= n:
        if n % d == 0:
            prim = False
        d = d + 1
if prim:
    print(n, "este prim")
else:
    print(n, "NU este prim")
Output real (rulat):
29 este prim
Bucla merge pana cand d*d depaseste n → complexitate O(√n), mult mai rapid decat O(n) pentru numere mari.
⚡ EXCLUSIV INTENSIV (C++): acelasi algoritm in C++

La specializarea intensiv informatica scriem si in C++. Acelasi test de primalitate, cu acelasi rationament O(√n):

#include <iostream>
using namespace std;

int main() {
    int n = 29;
    bool prim = (n >= 2);
    for (int d = 2; (long long)d * d <= n; d++) {
        if (n % d == 0) {
            prim = false;
        }
    }
    if (prim)
        cout << n << " este prim" << endl;
    else
        cout << n << " NU este prim" << endl;
    return 0;
}
Output real (compilat cu g++ -std=c++17, rulat):
29 este prim

Observa cum (long long)d * d protejeaza de depasire pentru n mare, iar logica este identica cu Python.

Exercitii practice

Exercitiul 1 (Nivel minim) - Suma cifrelor

Scrie un program care citeste un numar natural n si afiseaza suma cifrelor sale. Indiciu: foloseste n % 10 pentru ultima cifra si n // 10 pentru a o elimina, intr-o bucla while. Care este complexitatea fata de numarul de cifre?

Exercitiul 2 (Nivel standard) - Maximul si pozitia lui

Pentru sirul [4, 11, 2, 11, 8] afiseaza valoarea maxima si pozitia primei aparitii a acesteia. Atentie la cazul cu valori egale: trebuie sa retii prima pozitie, nu ultima.

Exercitiul 3 (Nivel performanta) - Optimizeaza numararea divizorilor

Rescrie algoritmul de numarare a divizorilor lui n astfel incat sa ruleze in O(√n) in loc de O(n), folosind faptul ca divizorii vin in perechi (d, n/d). Atentie la patratul perfect (cand d == n/d, divizorul se numara o singura data). Verifica pe n = 24 ca obtii tot 8 divizori.

Ce ai invatat astazi

  • Acumulator pentru suma (init 0) si produs / factorial (init 1) — O(n)
  • Minim si maxim printr-o singura parcurgere, init cu primul element — O(n)
  • Contor pentru numararea elementelor care respecta o conditie — O(n)
  • Divizorii unui numar si numararea lor — O(n), optimizabil la O(√n)
  • Test de primalitate pana la √n, cu justificarea perechilor de divizori — O(√n)
  • (Intensiv) acelasi test de primalitate in C++

Urmatoarea lectie

Aplicam toate aceste tipare pe probleme reale de tip Bacalaureat: trasarea codului, determinarea rezultatului si completarea codului.

Continua →