Two Pointers
Tehnica two pointers (doi pointeri) este o idee simplă, dar puternică: în loc să folosim o singură variabilă pentru a parcurge datele, folosim două: una care pornește de la început și una de la sfârșit (sau una lentă și una rapidă)
Am văzut-o deja fără să știm. Când verificam palindroamele, comparam primul caracter cu ultimul, apoi al doilea cu penultimul. Aceia erau doi pointeri
def este_palindrom(cuvant):
stanga = 0
dreapta = len(cuvant) - 1
while stanga < dreapta:
if cuvant[stanga] != cuvant[dreapta]:
return False
stanga += 1
dreapta -= 1
return True
print(este_palindrom("racecar"))
print(este_palindrom("hello"))
Ieșire
True
False
stanga pornește de la 0, dreapta pornește de la ultimul index. Comparăm, apoi îi mișcăm unul către celălalt. Când se întâlnesc la mijloc, am terminat
Alt exemplu clasic: având o listă sortată și o sumă țintă, găsește două numere care se adună până la țintă
Metoda brute force (buclă imbricată, verificând fiecare pereche) funcționează, dar este lentă. Cu doi pointeri pe o listă sortată, este mult mai inteligent
def doua_numere(numere, tinta):
stanga = 0
dreapta = len(numere) - 1
while stanga < dreapta:
suma_curenta = numere[stanga] + numere[dreapta]
if suma_curenta == tinta:
return (numere[stanga], numere[dreapta])
elif suma_curenta < tinta:
stanga += 1
else:
dreapta -= 1
return None
numere = [1, 2, 4, 7, 11, 15]
rezultat = doua_numere(numere, 9)
print(rezultat)
Rezultat (2, 7)
Cum funcționează? Adunăm cel mai mic număr (stanga) și cel mai mare (dreapta). Dacă suma este prea mică, avem nevoie de un număr mai mare → mută stanga spre dreapta. Dacă suma este prea mare, avem nevoie de un număr mai mic → mută dreapta spre stânga. Dacă este exact bună, am găsit perechea
Asta funcționează pentru că lista este sortată. Mutarea lui stanga crește suma, mutarea lui dreapta o scade. Restrângem din ambele părți până când găsim răspunsul (sau pointerii se întâlnesc, ceea ce înseamnă că nu există nicio pereche)
Un exemplu mai simplu: elimină duplicatele dintr-o listă sortată (păstrând doar elementele unice)
def elimina_duplicatele(numere):
if len(numere) == 0:
return []
rezultat = [numere[0]]
for i in range(1, len(numere)):
if numere[i] != numere[i - 1]:
rezultat.append(numere[i])
return rezultat
print(elimina_duplicatele([1, 1, 2, 2, 2, 3, 4, 4, 5]))
Rezultat [1, 2, 3, 4, 5]
Aici comparăm fiecare element cu cel anterior. Dacă sunt diferite, este o nouă valoare unică, deci păstreaz-o
Misiune: Perechi de Andocare
Navele care așteaptă să andocheze poartă fiecare o încărcătură de combustibil (sortată de la cea mai mică la cea mai mare). Două nave pot împărți o clemă de andocare doar dacă încărcăturile lor de combustibil se adună exact până la tinta. Găsește fiecare pereche validă.
Scrie o funcție pereche_cu_suma(numere, tinta) care primește o listă sortată și un număr țintă și returnează o listă cu toate perechile care se adună până la țintă. Folosește tehnica two pointers (un pointer la început, unul la sfârșit, mută-i unul către celălalt).
Apoi afișează Perechi: urmat de lista de perechi și Total perechi: urmat de câte sunt.
combustibili = [1, 2, 3, 4, 5, 6, 7, 8, 9]
tinta = 10
Ieșire
Perechi: [(1, 9), (2, 8), (3, 7), (4, 6)]
Total perechi: 4