Sunteți pe pagina 1din 32

Programarea

Algoritmilor (PA)
Seminar III
Punctaj seminar

● Maxim 1 punct
● 0.4p - raspunsuri (intrebarile apar cu albastru; max 1 rasp/sem)
● 0.6p - probleme suplimentare:
○ 0.1p - dificultate usoara ( nu neaparat putin cod)
○ 0.2p - dificultate medie
○ 0.4p - dificultate mare
○ o singura persoana poate raspunde la o problema; daca aveti alta
metoda de a rezolva problema puteti raspunde (NU for => while)
○ problemele pot fi rezolvate de toate grupele (144, 151, 152)
○ problemele vor fi verificate antiplagiat (0; luat de internet;
translatat codul C++ -> Python; folosit cod pe care nu il intelegeti)
Structuri de date
Introducere

● Vom studia structurile de date de baza oferite de Python


● Majoritatea structurilor sunt de tip Abstract Data Type (ADT)
ceea ce inseamna ca pot retine orice
● Operatiile uzuale pe aceste structuri sunt (difera complexitatea):
○ Adaugare element in structura
○ Stergere element din structura
○ Verificare daca un element exista in multime
● Fiind ADT-uri structurile se pot combina intre ele (ex: Max stack)
Structuri de date
Simple

● Liste (list)
○ mutable (elementele se pot modifica)
○ conteaza ordinea
○ retineti un numar arbitrar de elemente (ex: cuvinte dintr-o carte)
● Tupluri (tuple)
○ imutable (elementele nu se pot modifica)
○ conteaza ordinea
○ retineti un numar fix de elemente
Structuri de date
Operatii comune

● xs = ….. # definim o lista sau un tuplu


● n = len(xs) # numarul de elemente din structura
● x = xs[0] # salvam in x primul element
● for x in xs: # parcurgere elementele
○ print(x)
● for i in range( n): # alta metoda de a parcurgere
○ print(xs[i]) # folosind indexul elementelor
● 3 in xs: # verificam daca 3 se afla printre elemente
● x = x[::-1] # intoarce elementele (reverse)
Structuri de date
Liste - operatii

● xs = [] # lista vida
● xs.append(1) # adaugare element la final
● x = xs.pop() # stergere element de la final
● x = xs.pop(3) # stergere element de pe pozitia 3 (idx → 0)
● xs[1] = 3 # modificam valoarea de pe pozitia 1 in 3
Structuri de date
Tupluri - operatii

● xs = (1, 2, 3) # tuplul contine 3 elemente !nu se modifica!


● NU xs[1] = 3

Exemple:
# f : R -> RxR
● a=1 # f(x) = (x + 2, x^2 + 1)
● b=2 def f(x)
● (a, b) = (b, a) return (x+2, x**2 + 1)
Structuri de date
Liste - folosite ca vectori/matrici din C
xs = [0 for x in range( n)] # declaram o lista care contine n zerouri
xs[ n - 1] = 5 # fara declaratia anterioara (xs=[], eroare)

# n = coloane, m = linii; exemplu: n = 3, m = 2 # [[0,0,0]


matrice = [ [0 for x in range( n)] for y in range( m)] # [0,0,0]]

xs = [] xs.append(tmp)
for y in range( m):
tmp = [] print(xs)
for x in range( n):
tmp.append(0)
Structuri de date
Liste - exemplu
Primiti o lista de numere naturale mai mici decat 100. Sortati lista.
Exemplu:
Input: xs = [1,5,2,1,1,3,4,1,2] Output: [1, 1, 1, 1, 2, 2, 3, 4, 5]

Rezolvare simpla:
xs.sort()
print(xs)
sau:
print(sorted(xs))

Complexitatea uzuala a sortarii este O( n log n). Se poate mai bine?


Structuri de date
Liste - exemplu
Da! Sortare folosind vectori de frecventa.
n_max = 100
frecventa = [0 for x in range( n_max)]

for x in xs:
frecventa[x] += 1

for i in range( n_max):


while frecventa[i] != 0:
print(i)
frecventa[i] -= 1
Structuri de date
Avansate - Mutable

● Multimi (set) # {1, 2, 4, 5, 3}


○ nu conteaza ordinea
○ verificare rapida daca un element exista in multime O(1) vs O( n)
● Dictionare (dict) # {“mere”: 2, “pere”: 3}
○ nu conteaza ordinea
○ asociaza unei chei o valoare (cheia in stanga, valoarea in dreapta)
○ verificare rapida daca o cheie exista in multime
● Pentru verificare:
○ element in structra == True
Structuri de date
Multimi

● s = set() # se foloseste constructorul


● s = set([1, 2, 3]) # alta metoda de a initializa s-ul
● s = {1, 2, 3} # alta metoda de a initializa s-ul
● s.add(4) # adaugam elementul 1 la set
○ + s.add(4) # nu face nimic / operatia 1 este deja in s
● s.remove(1) # stergem elementul 1 din set
● if 3 in s: … # verificam daca 3 apare in s
● for x in s: # parcurgem setul
○ print(x):
Structuri de date
Exercitiu: aparitie cuvinte liste

prop = “Ana are cinci mere si Maria ia doua mere cate mere are Ana”
cautate = [“are”, “mere”, “iar”]

for cuvant in prop.split():


for cautat in cautate:
if cautat == cuvant:
print (“Cuvantul”, cautat, “apare in prop”)

# Cuvintele care apar de mai multe ori sunt afisate de mai multe ori
# Cum scapam de aceasta problema?
# Complexitate? ( presupunem ca avem n cuvinte in prop, m in cautate)
Structuri de date
Exercitiu: aparitie cuvinte liste

prop = “Ana are cinci mere si Maria ia doua mere cate mere are Ana”
cautate = [“are”, “mere”, “iar”]

for cuvant in prop.split():


for cautat in cautate:
if cautat == cuvant:
print (“Cuvantul”, cautat, “apare in prop”)
cautate.remove(cautat)
Structuri de date
Exercitiu: aparitie cuvinte liste

prop = “Ana are cinci mere si Maria ia doua mere cate mere are Ana”
cautate = [“are”, “mere”, “iar”]

for cuvant in prop.split():

if cuvant in cautate:
print (“Cuvantul”, cautat, “apare in prop”)
cautate.remove(cautat)

# Ce complexitate are codul acum?


Structuri de date
Exercitiu: aparitie cuvinte liste + set

prop = “Ana are cinci mere si Maria ia doua mere cate mere are Ana”
cautate = [“are”, “mere”, “iar”]

s = set()
for cuvant in prop.split():
for cautat in cautate:
if cautat == cuvant and not cautat in s:
print (“Cuvantul”, cautat, “apare in prop”)
s.add(cautat)

# Ce complexitate are codul acum?


Structuri de date
Exercitiu: aparitie cuvinte seturi

prop = “Ana are cinci mere si Maria ia doua mere cate mere are Ana”
cautate = [“are”, “mere”, “iar”]

s = set()
for cuvant in prop.split():
s.add(cuvant)

for cuvant in cautate:


if cuvant in s:
print (“Cuvantul”, cautat, “apare in prop”)
# Ce complexitate are codul acum?
Structuri de date
Exercitiu: aparitie cuvinte - Complexitate

● n - numar de cuvinte in lista; m - numar de cuvinte cautate


● Varianta cu liste:
○ O( n * m) # Pentru fiecare cuvant din lista parcurgem cautate
● Varianta cu liste + set:
○ O( n * m + m) # La fel ca mai sus + O( m) pentru m inserari in set
● Varianta cu set:
○ O( n + m) # O( n) pentru inserare in set, O( m) pentru verificare
● Cum putem rezolva problema altfel? Tot cu set-uri, dar in alta
ordine. Care este diferenta intre cele doua metode?
Structuri de date
Dictionare

● s = “ana are mere si are si pere”


● d = {} # initializare dictionar
● d[“ana”] = 1 # cheii “ana” ii asociem valoarea 1
● d[“are”] = 2 # cheii “are” ii asociem valoarea 2
● d[“mere”] = 1 # cheii “mere” ii asociem valoarea 1
● x = d[“are”] # x == 2
Structuri de date
Dictionare

● d = {2: “ana”, 3: “mere”, 4: 5}


● for key in d: # parcurgere pe chei
○ print(key, “=>” , d[key])
● for val in d.values(): # parcurgere valori
○ print(val)
● for key, val in d.items(): # parcurgere pe chei si valori
○ print(key, value)

Exercitiu: Afisati frecventa literelor dintr-un str. Metoda vector?


Exercitiu:
Afisati frecventa literelor dintr-un str

prop = “ana are cinci mere si maria ia doua mere cate mere are ana”

frecventa = [0 for x in range(26+1)] # definim vector cu 26 de numere


for litera in prop: # parcurgem literele
if litera >= ‘a’ and litera <= ‘z’: # consideram doar litere mici #isalpha
frecventa[ord(litera) - ord(‘a’)] += 1 # vectorul este intre 0 si 26

# Afisam rezultatul
for i in range(len(frecventa)):
print(‘Litera’, chr(ord(‘a’) + i), ‘apare de’, frecventa[i], ori)
Exercitiu:
Afisati frecventa literelor dintr-un str

prop = “Ana are cinci mere si Maria ia doua mere. Cate mere are Ana?”

d = {} # definim un dictionar gol


for litera in prop: # parcurgem literele
if litera in d: # daca litera se afla in dictionar
d[litera] += 1 # incrementam valoarea
else: # daca este prima data cand gasim lit
d[litera] = 1 # setam valoarea la 1

for key in d:
print(“Caracterul”, key, “apare de”, d[key])
Exercitiu:
Afisati frecventa cuvintelor dintr-un str

s = “Ana are cinci mere si Maria ia doua mere. Cate mere are Ana?”

s = s.replace(‘.’, ‘’).replace(‘?’, ‘’) # eliminam semnele de punctuatie


d = {} # definim un dictionar gol
for cuv in s.split(): # parcurgem s pe cuvinte
if cuv in d: # daca cuvantul se afla in dictionar
d[cuv] += 1 # incrementam valoarea
else: # daca este prima data cand gasim cuv
d[cuv] = 1 # setam valoarea la 1
Erori dictionare

● Daca folositi o cheie care nu exista primiti:


○ KeyError
● De aceea este bine sa verificati daca o cheie exista inainte sa o
folositi (exceptie daca parcurgeti pe chei (for k in d.keys())
● Alternativ puteti folosi:
○ from collections import defaultdict
○ d = defaultdict(int) # daca nu exista d[k] se seteaza implicit la 0
○ d = defaultdict(str) # daca nu exista d[k] se seteaza implicit la “”
Probleme (1)
Index litere

● Primiti un string. Trebuie sa afisati pentru fiecare litera la ce pozitii


apare in string. Exemplu: s = “ana are mere”,
a - [0, 2, 4] n - [1], r - [5, 10]
● Dictionarele sunt ADT, deci pot retine orice tip de date pt valori:
○ d = {}
○ d[‘a’] = [0, 2, 4]
○ print(d[‘a’])
● In schimb cheile trebuie sa nu fie structuri de tip mutable (list, set)
Probleme (2)
Index cuvinte

● Primiti un string. Trebuie sa afisati pentru fiecare cuvant la ce


pozitii apare in string. Exemplu: s = “ana are mere si ana vrea pere”,
ana - [0, 4] # pozitii intre cuvinte

are - [1]

● Primiti si un index. Trebuie sa raspundeti rapid la intrebarea: ce


cuvant apare pe pozitia respectiva in string (/ multe cuvinte foarte
lungi)?
Probleme (3)
Anagrame

Primiti doua cuvinte formate din litere mici. Verificati daca sunt
anagrame. Exemplu: “emerit” si “treime” sunt anagrame, dar
“emerit” si “treimi” nu sunt.

Metoda bruta - complexitate?

Metoda eficienta fara alocare de memorie - complexitate?

Metoda eficienta cu alocare de memorie - complexitate?


Square Root Decomposition

Este o tehnica de programare folosita de obicei cand avem o


multime de elemente care se pot modifica si apoi trebuie sa
raspundem unor intrebari legate de intreaga multime.

Problema: Se da un sir care contine N numere intregi si M operatii


de doua tipuri:

● operatie de tipul 1 a b: afisati care este suma elementelor afate


intre pozitiile a si b;
● operatie de tipul 2 a b: valoarea elementului de pe pozitia a va
deveni b.
Square Root Decomposition
Exemplu:
Se da un sir care contine N numere intregi si M operatii (1-+, 2-mod).

Input: Output:

12 7 66
2 9 0 5 1 8 7 3 10 4 11 6 30
1 0 11 43
225 68
105
1 5 10
264
147
1 0 11
Square Root Decomposition
Simplificare

Solutia bruta - complexitate?

Presupunem ca avem doar operatii de tipul 1 (suma):

Solutie mai eficienta - folosind memorie O( n2) - complexitate 1/2?


Solutie mai eficienta - folosind memorie O( n) - complexitate?

De ce nu functioneaza daca avem si operatii de tipul 2?


Imbunatatire performanta rulare algoritm cand avem si operatii 2?
Square Root Decomposition

Rezolvare: Vom imparti sirul initial in parti de √N si pentru fiecare


parte vom memora care este suma din acea parte. Cand vom
modifica un element, vom modificam si suma care se afla in partea
respectiva.

Vom indexa vectorii de la zero.


Square Root Decomposition

0 1 2 3 4 5 6 7 8 9 10 11

2 9 0 5 1 8 7 3 10 4 11 6

11 14 20 21

Operatii: Operatii:
1 0 11 -> cum mergem? 225 -> ce facem?
1 5 10 -> cum mergem?
Complexitati ( pe 1 si 2)?

S-ar putea să vă placă și