1. Subsecventa vs. subsir
v[0..n-1] este portiunea v[l..r] formata din elemente consecutive: v[l], v[l+1], ..., v[r], unde 0 ≤ l ≤ r ≤ n-1.Lungimea subsecventei
v[l..r] este r − l + 1.
- Subsecventa = portiune continua, fara salturi (contiguous subarray in engleza)
- Subsir = elemente extrase in ordine, dar nu neaparat consecutive (pot fi salturi)
v[2..5] = [4, 1, 5, 9]→ subsecventa de lungime 4, suma = 19v[0..7]→ intregul vector, suma = 31[3, 4, 5]→ NU este subsecventa (sare indicii 1 si 3)v[5..5] = [9]→ subsecventa de lungime 1 (un singur element)
2. Sume partiale (prefix sums) — interogare O(1)
sp are n+1 elemente:sp[0] = 0 sp[i] = sp[i-1] + v[i-1] pentru i = 1..nFormula cheie: suma subsecventei
v[l..r] = sp[r+1] − sp[l] in O(1).
# Sume partiale pentru vectorul v v = [3, 1, 4, 1, 5, 9, 2, 6] n = len(v) # Construire O(n): sp[0]=0, sp[i]=sp[i-1]+v[i-1] sp = [0] * (n + 1) for i in range(n): sp[i+1] = sp[i] + v[i] print("Vector v: ", v) print("Sume partiale: ", sp) # Interogare O(1): suma v[l..r] = sp[r+1] - sp[l] l, r = 2, 5 suma_lr = sp[r+1] - sp[l] print(f"suma({l},{r}) = sp[{r+1}] - sp[{l}] = {sp[r+1]} - {sp[l]} = {suma_lr}")
Vector v: [3, 1, 4, 1, 5, 9, 2, 6] Sume partiale: [0, 3, 4, 8, 9, 14, 23, 25, 31] suma(2,5) = sp[6] - sp[2] = 23 - 4 = 19
- Fara sume partiale: suma(l,r) costa O(r−l+1). Cu Q interogari: O(n·Q) total.
- Cu sume partiale: preprocesare O(n), fiecare interogare O(1). Cu Q interogari: O(n+Q) total.
- La n=100.000 si Q=50.000: diferenta intre 5 miliarde vs 150.000 operatii.
3. Cea mai lunga secventa cu proprietate data — O(n)
lung_cur (lungimea secventei curente) si lung_max (maximul gasit). La fiecare pas: daca proprietatea continua, incrementam; daca nu, resetam la 1.
# Cea mai lunga secventa strict crescatoare consecutiva v = [2, 4, 6, 3, 5, 1, 7, 8, 9] n = len(v) lung_max = 1 lung_cur = 1 end_m = 0 # indicele de sfarsit al secventei maxime for i in range(1, n): if v[i] > v[i-1]: # proprietatea: strict crescator lung_cur += 1 else: lung_cur = 1 # rupe secventa: resetam if lung_cur > lung_max: lung_max = lung_cur end_m = i start_m = end_m - lung_max + 1 print("Vector:", v) print(f"Secventa strict crescatoare: v[{start_m}..{end_m}] = {v[start_m:end_m+1]}") print(f"Lungime: {lung_max}")
Vector: [2, 4, 6, 3, 5, 1, 7, 8, 9] Secventa strict crescatoare: v[5..8] = [1, 7, 8, 9] Lungime: 4
- Secventa de elemente egale:
if v[i] == v[i-1] - Secventa nedescrescatoare:
if v[i] ≥ v[i-1] - Secventa de elemente pare:
if v[i] % 2 == 0(si initializeazalung_cur = 1 if v[0]%2==0 else 0)
4. Secventa de suma maxima — Algoritmul Kadane O(n)
v[l..r] cu suma maxima (vectorul poate contine si numere negative).Algoritmul Kadane: la fiecare pozitie
i, decidem daca extindem secventa curenta sau incepem una noua. Regula: daca suma_cur < 0, ea numai scade suma viitoare, deci incepem de la v[i].
# Kadane: secventa de suma maxima O(n) v = [-2, 1, -3, 4, -1, 2, 1, -5, 4] n = len(v) suma_max = v[0] # initializare cu v[0], nu cu 0! suma_cur = v[0] s = 0; e = 0; ts = 0 # start/end al secventei maxime; ts = temp_start for i in range(1, n): if suma_cur + v[i] < v[i]: # echivalent: suma_cur < 0 suma_cur = v[i] # incepem secventa noua de la i ts = i else: suma_cur = suma_cur + v[i] # extindem secventa curenta if suma_cur > suma_max: suma_max = suma_cur s = ts; e = i print("Vector:", v) print(f"Suma maxima = {suma_max}") print(f"Secventa: v[{s}..{e}] = {v[s:e+1]}")
Vector: [-2, 1, -3, 4, -1, 2, 1, -5, 4] Suma maxima = 6 Secventa: v[3..6] = [4, -1, 2, 1]
| i | v[i] | suma_cur | suma_max | Actiune |
|---|---|---|---|---|
| init | -2 | -2 | -2 | start |
| 1 | 1 | 1 | 1 | -2+1<1 → restart de la i=1 |
| 2 | -3 | -2 | 1 | 1-3=-2, extinde (1≥0) |
| 3 | 4 | 4 | 4 | -2+4<4 → restart de la i=3 |
| 4 | -1 | 3 | 4 | 4-1=3, extinde |
- Initializeaza
suma_max = v[0], nu 0 (altfel dai gres cand toate elementele sunt negative) - Daca toate elementele sunt negative, Kadane returneaza corect maximul (cel mai putin negativ)
5. Sume partiale in C++ EXCLUSIV INTENSIV
Acelasi algoritm de sume partiale implementat in C++. Diferente fata de Python: declarare explicita de tip si dimensiune, initializare cu = {0} (seteaza TOATE elementele la 0), indexare identica.
#include <iostream> using namespace std; int main() { int v[] = {3, 1, 4, 1, 5, 9, 2, 6}; int n = 8; int sp[9] = {0}; // initializeaza TOATE cele 9 elemente la 0 for (int i = 0; i < n; i++) sp[i+1] = sp[i] + v[i]; // Afisare sp cout << "sp = ["; for (int i = 0; i <= n; i++) { if (i) cout << ", "; cout << sp[i]; } cout << "]" << endl; // Interogare: suma v[2..5] in O(1) int l = 2, r = 5; cout << "suma(2,5) = sp[6] - sp[2] = " << sp[r+1] << " - " << sp[l] << " = " << (sp[r+1] - sp[l]) << endl; return 0; }
sp = [0, 3, 4, 8, 9, 14, 23, 25, 31] suma(2,5) = sp[6] - sp[2] = 23 - 4 = 19
Rezultatul este identic cu Python. Logica matematica a algoritmului nu depinde de limbaj — doar sintaxa difera.
6. Aplicatie: numararea subsecventelor cu suma data
# Numara subsecventele cu suma egala cu target v = [1, 2, 3, 4, 5] n = len(v) target = 5 # Construim sume partiale sp = [0] * (n + 1) for i in range(n): sp[i+1] = sp[i] + v[i] contor = 0 for l in range(n): for r in range(l, n): if sp[r+1] - sp[l] == target: contor += 1 print(f" v[{l}..{r}] = {v[l:r+1]}, suma = {target}") print(f"Total subsecvente cu suma {target}: {contor}")
v[1..2] = [2, 3], suma = 5 v[4..4] = [5], suma = 5 Total subsecvente cu suma 5: 2
- v[1..2] = [2, 3]: 2 + 3 = 5 ✓
- v[4..4] = [5]: 5 = 5 ✓
- v[0..1] = [1, 2] = 3 ≠ 5; v[0..2] = 6 ≠ 5; v[2..3] = 7 ≠ 5 etc.