Documente Academic
Documente Profesional
Documente Cultură
Exista totusi si o solutie mai scurta, ce foloseste idea de nod incet / rapid. Mai exact,
nodul incet parcurge lista element cu element, in timp ce nodul rapid o parcurge din 2 in 2.
Atunci cand nodul rapid ajunge la finalul listei, nodul incet se afla fix la mijlocul ei (dupa
definitia din cerinta). Pentru ce nodul rapid este mereu in fata celui incet, trebuie sa-l
verificam doar pe el ca nu atinge finalul. De asemenea, pentru ca sare din 2 in 2, trebuie sa
veriicam ca exista atat el, cat si elementul urmator (atlfel nu ar putea ajunge peste 2
elemente). Algoritmul are aceeasi complexitate O(N), dar se scrie mai usor. Codul este
prezentat mai jos.
Este o lista ciclica? (3p)
Solutia primitiva, ca si in cazul anterior este sa facem fix ce ne spune problema. Mai
exact, parcurgem lista in timp ce numaram pozitia actuala. Pentru fiecare nod, verificam
daca prima lui aparitie in lista coincide cu indexul. Daca nu, inseamna ca nodul s-a repetat,
deci avem ciclu. Codul este prezentat mai jos.
Complexitatea solutiei este O(N2), si din pacate nu intra in timp pentru testul cel
mare. Este necesar deci sa gasim o solutie mai eficienta.
Revenim la idea de nod incet / rapid. Stim deja ca daca lista nu este ciclica, nodul
rapid ajunge la final in complexitate O(N). Ce se intampla totusi daca lista are ciclica? Sa
presupunem ca lista este ciclica, si ciclul incepe pe o pozitie aleatoare. Atunci cand nodul
incet intra in ciclul, nodul rapid deja se afla in el. Fie K distanta dintre cele 2 cand nodul incet
intra in ciclu. La fiecare pas, distanta dintre cele noduri creste cu 1. Fie C lungimea ciclului.
Daca la fiecare pas distanta creste, inseamna ca va exista un moment cand distanta va fi
egala cu C. Acest lucru inseamna ca cele 2 noduri se suprapun (mai exact, nodul rapid a
facut unul sau mai multe cicluri intregi si a ajuns peste cel incet). Deci avem nevoie sa
creasca distanta de la K la C. In cel mai rau caz K = 1 si C = N, deci avem nevoie de N
operatii, de unde rezulta complexitatea solutiei ca fiind O(N) si pentru cazul in care lista este
ciclica. Codul este prezentat mai jos.
Este o lista palindrom? (2p)
Solutia primitiva este formata din mai multi pasi. Primul este sa construim o lista
noua, dar care contine valorile din lista originala in ordine inversa. Pentru a realiza acest
lucru, parcurgem lista originala, construim un nou nod ce contine aceeasi informatie ca cel
din lista originala si-l legam de nodul anterior creat. Complexitatea acestui pas este O(N).
Codul este prezentat mai jos.
Dupa ce avem atat lista originala, cat si cea inversata, trebuie sa le comparam
element cu element. Daca 2 elemente sunt diferite, lista nu e palindom. Complexitatea
pasului este O(N). Codul este prezentat mai jos.
Functia de verificare nu tine cont de faptul ca cele 2 liste au acelasi numar de
elemente, motiv pentru care verifica ca ambele sa ajunga la finalul lor, in loc sa intoarca
direct valoarea adevarat.
Nu in ultimul rand, trebuie tinut cont de faptul ca am construit o noua lista, deci
trebuie sa o distrugem. Stergem pe rand fiecare nod din lista inversata. Complexitatea
acestui pas este O(N). Complexitatea finala a algoritmului este O(N) + O(N) + O(N) = O(N).
Codul pentru stergerea listei, cat si pentru combinarea pasilor este prezentat mai jos.
Desi algoritmul are complexitate O(N) si primeste punctaj maxim, solutia nu este
eficienta deoarece construieste o noua lista pentru care dubleaza memoria listei originale.
Pentru a rezolva problema fara spatiu suplimentar, inversam a 2-a jumatate a listei.
Folosind ideile din prima problema, gasim elementul de dinainte de mijloc. Indexul lui este
(n-1)/2. Adaptam functia de inversat sa modifice lista (in loc sa construiasca una noua), si
modificam si functia care verifica daca 2 liste sunt egale astfel incat sa verifice daca valorile
din 2 serii de noduri sunt egale pana unul dintre ele ajunge la null. Codul este prezentat mai
jos. Functiile care nu sunt afisate au fost deja prezentate.
Mediana unei liste (bonus)
Solutia primita de a sorta lista si apoi a extrage elementul din mijloc are o
complexitate de O(N * logN) motiv pentru care nu trece nici un test.
Problema generala, gasirea celui mai mic K element intr-o colectie nesortata poarta
numele de problema de selectie. Mai multe informatii despre ea puteti gasi la
https://en.wikipedia.org/wiki/Selection_algorithm
Alegem ca pivot primul element din lista. Deoarece se garanteaza faptul ca lista va fi
generata aleator, ne putem astepta ca numarul de elemente mai mici decat pivotul sa fie
egal cu numarul de elemente mai mari decat pivotul. De asemenea, declaram si cele 3
colectii mentionate anterior. Adaugam in plus si numarul de elemente pentru fiecare colectie
in parte.
Dupa ce am parcurs toata lista trebuie sa ne asiguram ca cele 3 noi liste sunt valid
conform definitiei (dupa ultimul element urmeaza pointerul null). In mod sigur exista
elemente egale cu pivotul, pentru celelalte 2 liste trebuie verificat daca a existat un astfel de
element.