De ce contează?
Scrii cuvântul „rotor” pe o foaie transparentă și o întorci cu spatele spre lumină. Surpriză: citești tot „rotor”. Cuvintele care arată la fel și de la stânga la dreapta, și de la dreapta la stânga se numesc palindroame. Întrebarea e: cum verifici asta repede, fără să întorci foaia de fiecare dată?
Intuiția
Un palindrom e simetric față de centrul lui: primul caracter trebuie să fie egal cu ultimul, al doilea cu penultimul și așa mai departe spre mijloc. Nu trebuie să compari tot șirul cu o copie întoarsă — îți ajunge să verifici că fiecare pereche de capete care se „oglindesc” coincide. Pui un deget la început și unul la final și îi apropii unul de celălalt.
Vezi cum funcționează
Pornește animația și urmărește cei doi pointeri: unul pleacă din stânga, celălalt din dreapta, și se apropie de centru. La fiecare pas compară perechea de capete; dacă toate coincid până se întâlnesc la mijloc, șirul e palindrom.
Folosește ← și → ca să pășești comparație cu comparație, sau Redă pentru animație. Observă cum cei doi pointeri fac împreună un singur drum până la centru — de aceea verificarea costă doar jumătate din lungimea șirului.
Prima idee: construiești șirul inversat (r-o-t-o-r citit invers tot r-o-t-o-r)
și verifici dacă inversul e identic cu originalul. Simplu și corect.
Funcționează, dar irosești memorie: ca să faci copia inversată îți trebuie încă
un șir de lungime n, adică O(n) memorie în plus, degeaba. Pentru n mare e
risipă, iar la concurs vrei soluția cu cel mai mic cost posibil.
Nu am nevoie de copie: caracterul de pe poziția st trebuie să fie egal cu cel
de pe poziția oglindă din dreapta. Pot compara direct capetele care se oglindesc,
fără să construiesc nimic.
Pun st la început și dr la final. Cât timp st < dr, compar s[st] cu
s[dr]; dacă diferă, NU e palindrom. Altfel avansez st la dreapta, dr la
stânga. Dacă ajung la mijloc fără nepotrivire, e palindrom. Costă O(n) timp,
O(1) memorie.
Algoritmul pas cu pas
Fie șirul rotor, cu indici de la 0 la 4. Punem st = 0 și dr = 4.
Pasul 1. Comparăm capetele: s[0] cu s[4].
r | o | t | o | r |
0 | 1 | 2 | 3 | 4 |
st | dr |
Pasul 2. Avansăm: st = 1, dr = 3. Comparăm s[1] cu s[3].
r | o | t | o | r |
0 | 1 | 2 | 3 | 4 |
st | dr |
Pasul 3. Acum st = 2, dr = 2: pointerii s-au întâlnit la mijloc.
r | o | t | o | r |
0 | 1 | 2 | 3 | 4 |
mijloc |
Nicio pereche n-a diferit, deci rotor este palindrom.
Pentru un șir de lungime impară, caracterul din mijloc rămâne mereu nepereche și
nu trebuie verificat — el se oglindește în el însuși. La lungime pară, pointerii
se „depășesc” direct (st ajunge mai mare ca dr) fără să rămână vreun caracter
central. În ambele cazuri faci cel mult n/2 comparații.
Pentru contrast, pe carte: prima pereche e s[0]='c' și s[4]='e'. Sunt
diferite, deci te oprești imediat — carte nu este palindrom, fără să mai
verifici restul.
Implementare C++
#include <iostream>
#include <string>
using namespace std;
// returneaza true daca s se citeste la fel in ambele sensuri
bool estePalindrom(const string &s) {
int st = 0;
int dr = s.size() - 1;
while (st < dr) {
if (s[st] != s[dr]) {
return false; // o pereche difera -> nu e palindrom
}
st++; // avansam spre centru
dr--;
}
return true; // toate perechile au coincis
}
int main() {
string s = "rotor";
if (estePalindrom(s)) {
cout << s << " este palindrom";
} else {
cout << s << " nu este palindrom";
}
// rotor este palindrom
return 0;
}Complexitate
| Caz | Timp | Spațiu |
|---|---|---|
| Cel mai bun (capete diferite din start) | O(1) | O(1) |
| Mediu / cel mai rău (palindrom) | O(n) | O(1) |
Verifici cel mult n/2 perechi, deci timpul e O(n). Nu construiești nicio
copie, folosești doar doi indici, deci memoria suplimentară e O(1).
Trei capcane frecvente:
- Compari tot șirul, nu te oprești la mijloc. Dacă scrii bucla cu
while (st < dr)te oprești corect la centru. Dacă, din greșeală, mergi până la capăt (st <= drcu pointeri care trec unul de altul, sau parcurgi tot șirul), ajungi să compari aceleași perechi de două ori — muncă inutilă și logică confuză. - Case-sensitivity.
Rotorcu „R” mare NU e tratat ca palindrom de cod, fiindcă'R'(cod ASCII 82) diferă de'r'(cod ASCII 114). Dacă vrei să ignori diferența majuscule/minuscule, aduci întâi totul la litere mici cutolower. - Spațiile și semnele. La fraze de tip „ele fac cafea cafe..." spațiile și punctuația strică simetria. Dacă enunțul cere să le ignori, le elimini din șir înainte să pornești cei doi pointeri.