Funcția de prefix

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 12 aprilie 2022; verificările necesită 4 modificări .

Funcția de prefix a unui șir și o poziție în acesta este lungimea celui mai mare prefix propriu (nu este egal cu întregul subșir) al subșirului , care este și sufixul acestui subșir.

Adică, la începutul unui subșir de lungime , trebuie să găsiți un astfel de prefix de lungime maximă care ar fi sufixul acestui subșir .

Notat ; unde  este un șir;  este lungimea subşirului în S. Se presupune că .

Adesea funcția de prefix este definită sub formă vectorială:

Funcția de prefix a unui șir este un vector , fiecare element fiind egal cu .

De exemplu, pentru un șir, funcția de prefix ar fi: .

Această funcție este utilizată, de exemplu, în algoritmul Knuth-Morris-Pratt .

Algoritm de calcul

Caută silabe repetate nu într-un cuvânt, ci într-un text, o linie care începe de la primele caractere? Caracterele rând sunt numerotate de la 1.

Lasă . Să încercăm să calculăm funcția de prefix pentru .

Dacă , atunci, desigur, . Dacă nu, încercați sufixe mai mici. Nu este necesar să repetați toate sufixele cu o căutare liniară. Puteți utiliza valorile deja calculate ale funcției de prefix. Puteți vedea că acesta va fi și sufixul șirului , deoarece  este lungimea prefixului-sufix maxim în acest moment. Pentru orice șir, nu va exista sufix. Astfel, algoritmul rezultă:

  1. Când  - pune .
  2. În caz contrar, când  - pune .
  3. În caz contrar, instalați și treceți la pasul 1.

Pentru un șir , 'abcdabcabcdabcdab'calculul ar fi:

1 S[1]='a', k=π=0; 2 S[2]='b'!=S[k+1] => k=π=0; 3 S[3]='c'!=S[1] => k=π=0; 4 S[4]='d'!=S[1] => k=π=0; 5 S[5]='a'==S[1] => k=π=1; 6 S[6]='b'==S[2] => k=π=2; 7 S[7]='c'==S[3] => k=π=3; 8 S[8]='a'!=S[4] => k:=π(S, 3)=0, S[8]==S[1] => k=π=1; 9 S[9]='b'==S[2] => k=π=2; 10 S[10]='c'==S[3] => k=π=3; 11 S[11]='d'==S[4] => k=π=4; 12 S[12]='a'==S[5] => k=π=5; 13 S[13]='b'==S[6] => k=π=6; 14 S[14]='c'==S[7] => k=π=7; 15 S[15]='d'!=S[8] => k:=π(S, 7)=3, S[15]==S[4] => k=π=4; 16 S[16]='a'==S[5] => k=π=5; 17 S[17]='b'==S[6] => k=π=6;

Iar rezultatul este: [0,0,0,0,1,2,3,1,2,3,4,5,6,7,4,5,6].

Viteza de lucru

În ciuda faptului că elementul 3 este o buclă interioară, timpul de calcul al funcției de prefix este estimat ca . Să demonstrăm.

Toate sunt împărțite în:

  1. crescând cu unu. Bucla trece printr-o iterație.
  2. Nu se schimbă zero . De asemenea, bucla trece printr-o iterație. Cazurile 1 și 2 în total nu mai mult de bucăți.
  3. Nu schimbați sau reduceți pozitivul . Deoarece valoarea poate scădea doar în interiorul buclei, iar creșterea este posibilă doar cu una, valoarea totală nu poate scădea de mai multe ori, ceea ce limitează numărul de ori se execută bucla interioară.

În total, algoritmul nu necesită mai mult decât iterații, ceea ce demonstrează ordinea vitezei . „Cel mai rău” pentru algoritm este cazul procesării unui șir de forma . 'aa…ab'

Exemplu de implementare în Python

def prefix ( s ):     p = [ 0 ] * len ( s )     pentru i în interval ( 1 , len ( s )):         k = p [ i - 1 ]         în timp ce k > 0 și s [ k ] != s [ i ]:             k = p [ k - 1 ]         dacă s [ k ] == s [ i ]:             k += 1         p [ i ] = k     return p

Link -uri