De ce contează?
Citești un cuvânt cu degetul, literă cu literă, de la stânga la dreapta. În timp ce degetul înaintează, poți ține minte simultan câte vocale ai văzut, câte consoane și câte cifre — fără să te întorci. O singură plimbare a degetului îți răspunde la toate întrebările deodată. Exact așa parcurgi un string în C++.
Intuiția
Un string este o secvență de caractere numerotate de la 0 la s.length() - 1 — practic un vector de litere. Multe întrebări despre un text se reduc la „uită-te la fiecare caracter o dată”: câte vocale are? câte cifre? cum arată scris cu majuscule?
Cheia este că nu ai nevoie de mai multe treceri. La fiecare caracter poți decide pe loc ce-i actualizezi, iar la final ai toate răspunsurile. O singură plimbare prin șir, cost proporțional cu lungimea lui.
Vezi cum funcționează
Urmărește cum degetul (indexul i) avansează caracter cu caracter prin șir, iar contoarele se actualizează la fiecare pas:
Folosește ← și → ca să pășești caracter cu caracter, sau Redă pentru animație. Observă cum un singur pas e suficient pentru a aduna tot ce te interesează.
Vrei să afli câte vocale, câte consoane și câte cifre are șirul. Prima idee: faci o buclă care numără vocalele, apoi a doua buclă care numără consoanele, apoi a treia pentru cifre. Trei întrebări, trei treceri.
Funcționează, dar treci de 3 ori prin același șir. Pe „algoritmica” (11 caractere) faci 33 de pași în loc de 11. La un text de un milion de caractere, faci 3 milioane de operații degeaba — risipă pură.
Toate întrebările se uită la același caracter. Când degetul e pe poziția i, pot decide într-o clipă dacă e vocală, consoană sau cifră și să cresc contorul potrivit — fără să mai parcurg șirul a doua oară.
O singură buclă, mai multe acumulatoare. La fiecare caracter actualizezi simultan toate contoarele de care ai nevoie. O trecere O(n), oricâte întrebări ai.
Algoritmul pas cu pas
Luăm șirul s = "algoritmica" și numărăm vocalele într-o singură trecere. Pornim cu vocale = 0 și mutăm indexul i de la 0 spre coadă. La fiecare caracter verificăm dacă e una dintre a, e, i, o, u:
a | l | g | o | r | i | t | m | i | c | a |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
Urmărim contorul pas cu pas, caracter cu caracter:
i = 0:'a'e vocală →vocale = 1i = 1:'l'consoană → rămâne1i = 2:'g'consoană → rămâne1i = 3:'o'e vocală →vocale = 2i = 5:'i'e vocală →vocale = 3i = 8:'i'e vocală →vocale = 4i = 10:'a'e vocală →vocale = 5
Dacă aveam nevoie și de numărul de consoane sau de cifre, le adăugam ca alte acumulatoare în aceeași buclă. Nu costă o trecere în plus — costă doar un if în plus per caracter.
Implementare C++
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "algoritmica";
int vocale = 0, consoane = 0, cifre = 0;
// o singura trecere prin sir, toate contoarele deodata
for (int i = 0; i < (int)s.length(); i++) {
char c = s[i];
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
vocale++;
} else if (c >= 'a' && c <= 'z') {
consoane++;
} else if (c >= '0' && c <= '9') {
cifre++;
}
}
cout << vocale << "\n"; // 5 vocale
cout << consoane << "\n"; // 6 consoane
cout << cifre << "\n"; // 0 cifre
return 0;
}Aceeași parcurgere se poate scrie și cu range-based for, când ai nevoie doar de valoarea caracterului, nu de poziția lui:
int vocale = 0;
for (char c : s) { // c ia pe rand fiecare caracter
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
vocale++;
}
}
// vocale == 5 pentru "algoritmica"Complexitate
| Caz | Timp | Spațiu |
|---|---|---|
| Orice caz | O(n) | O(1) |
Parcurgem șirul o singură dată (n = lungimea lui), iar pe lângă șir folosim doar câteva variabile contor, indiferent cât de lung e textul. Adăugarea de noi întrebări (consoane, cifre) nu schimbă O(n) — rămâne o singură trecere.
Trei capcane frecvente la parcurgerea unui string:
s.length()apelat în condiție de mii de ori.for (int i = 0; i < s.length(); i++)recheamăs.length()la fiecare pas. Pentrustd::stringe O(1), deci e tolerabil — dar pe șiruri foarte lungi e mai curat să salveziint n = s.length();o singură dată și să comparii < n.- Off-by-one la indici. Pozițiile valide sunt de la
0lan-1. Dacă scriii <= s.length(), ajungi pe pozițian, care nu există — citire în afara șirului. - Modifici șirul în timp ce-l parcurgi. Dacă ștergi sau inserezi caractere în
schiar în buclă, lungimea se schimbă sub tine și indexuliajunge să sară peste caractere sau să iasă din șir. Dacă trebuie să transformi (de exemplu majuscule), modifică doars[i]pe loc, fără să schimbi lungimea.