Documente Academic
Documente Profesional
Documente Cultură
Vom numi subșirul a cărui apariție se caută model iar șirul în care se caută text.
Fie
T[1..n] – textul de lungime n
P[1..m] – modelul de lungime m, mn
Textul și modelul sunt, de obicei șiruri de caractere.
Sunt generate pe rând toate deplasamentele posibile (între 0 și n – m + 1) și pentru fiecare deplasament sunt verificate
m caractere din text.
pentru s 0, n – m + 1 executa
ok 1
pentru i 0, m – 1 executa
daca t[s + i] ≠ p[i] atunci
ok 0
sf. daca
sf. pentru
daca ok = 1 atunci
scrie s
sf. daca
sf. pentru
Complexitate O(m * (n – m + 1))
Algoritmul se bazează pe compararea caracterelor din text cu caracterele din model (ca și algoritmul naiv), dar
folosește comparațiile făcută pentru a determina care este următorul deplasament de la care merită să fie făcute noi
comparații. Să presupunem că la un moment dat, pentru un deplasament oarecare, am găsit că k caractere din text
corespund cu primele k caractere din model (T[i … i + k - 1] = P[1 … k]). După ce am investit timp în găsirea acestei
potriviri parțiale putem folosi aceste date în două moduri:
- să sărim peste câteva deplasamente pentru care potrivirea totală nu e posibilă;
- după ce am potrivit modelul într-un deplasament posibil să sărim peste comparația unor caractere care știm că
vor coincide.
Fie T = xyxxyxyxyyxyxyxyyxyxyxxy și P = xyxyyxyxyxx
Pentru început vom alinia modelul la începutul textului și vom începe să comparăm caracter cu caracter:
Observăm că P[1 . . 3] corespunde cu T[1 . . 3] și găsim o nepotrivire pentru P[4] ≠ T[4]. Bazându-ne pe faptul că
P[1 . . 3] = T[1. . 3] și ignorând simbolurile din text și model de după poziția 3, care este următorul deplasament
pentru care putem avea o corespondență (fie ea și parțială)? Observăm că nu are rost să utilizăm deplasamentul 2, vom
alinia modelul în poziția 3. Dar în momentul alinierii știm că P[1] = T[3], așa că următoarea comparație va fi între
P[2] și T[4].
Observăm că P[4] ≠ T[2] așa că, ignorând caracterele de după T[4] următorul deplasament posibil apare în poziția 4.
Observăm că P[1 .. 4] corespunde cu T[4 .. 7] și apare o nepotrivire pentru P[5] ≠ T[8]. Ignorând caracterele din text
de după poziția 7 și din model de după poziția 4, care este următorul deplasament pentru care poate exista o
corespondență? Un deplasament posibil este poziția 6, potrivim modelul în poziția 6, dar în momentul potrivirii știm
că P[1 . . 2] = T[6. . 7] așa că vom începe compararea lui P[3] și T[8].
Aliniem modelul în poziția 6 și începem să comparăm caracter cu caracter P[3] = T[8], P[4] = T[9] … P[10] = T[15].
Observăm că P[1 . . 10] = T[6 . . 15] și că prima nepotrivire descoperită e pentru P[11] ≠ T[16]. Ignorând
caracterele din text de după poziția 15 și din model de după poziția 10, care este următorul deplasament pentru care
poate apărea o potrivire? Observăm că posibilul deplasament este 13, așezăm modelul în poziția 13, dar în acest
moment știm că P[1 . . 3] = T[13 . . 15].
Aliniem modelul în poziția 13, știm că P[1 . . 3] = T[13 . . 15], com compara P[4] cu T[16], P[5] cu T[17] etc..
Se găsește o potrivire totală pentru deplasamentul 13. Următoarea posibilă potrivire ar fi pentru deplasamentul 23, dar
aceasta nu mai poate conține o potrivire, așa că algoritmul se oprește.
Să notăm cu π(k) valoarea pentru care P[1, . . . , π(k)] este cel mai lung prefix propriu al lui P[1 . . k] care este și sufix
al acestui șir. În acest caz modelul se mută astfel încât P[1, . . . , π(k)] să fie aliniat cu T[i − π(k) + 1, . . . , i]
Algoritmul KMP determină pentru fiecare k, care este lungimea celui mai lung prefix propriu al lui P, care este și
sufix al acestuia. Valoarea π(k) se numește funcție prefix. Funcția este definită printr-un tablou cu m elemente, tablou
care reține în elementul de indice k o valoare care indică cel mai lung prefix propriu al lui P[1 . . k] care este și sufix.
k 1 2 3 4 5 6 7 8 9 10 11
P x y x y y x y x y x x
π(k) 0 0 1 2 0 1 2 3 4 3 1
În concluzie, dacă P[1, . . . , k] se potrivește cu T[i − k + 1, . . . , i], algoritmul KMP va compara pe P[k+1] cu T[i+1]
și va face unul din următorii pași:
- dacă P[k+1] = T[i+1] lungimea subșirului care corespunde se extinde (dacă k + 1 == m am găsit întregul
model în text).
- dacă P[k+1] ≠ T[i+1], modelul se mută spre dreapta cu k - π(k) poziții.
Pentru determinarea valorilor lui π(k) algoritmul KMP va face o preprocesare. Se va suprapune modelul cu el insusi.
Ne vom folosi de următoarele observații:
- valoarea lui π(1) = 0 (cel mai lung prefix propriu, adică de o lungime strict mai mică decât lungimea șirului
inițial este 0).
- dacă P[1, . . . , π(k)] este cel mai lung prefix propriu al lui P[1 . . k] care este și sufix al acestuia, atunci P[1, .
. . , π(k-1)] este cel mai lung prefix propriu al lui P[1 . . k-1].
Să presupunem că am determinat π(i) și vrem să determinăm π(i+1). Sa notam k = π(i). Verificăm dacă P[k +
1] se potriveste cu P[i + 1]. În caz afirmativ π(i+1) = k + 1. În caz contrar căutăm cel mai lung prefix care e și sufix la
care putem adăuga caracterul de pe poziția i + 1.
//pi[i] – lungimea celui mai lung prefix propriu care e si sufix pt P[0..i]
n lungime(T), m lungime (P)
pi[0] 0 //totdeauna
k 0 // k = lungimea celui mai lung prefix propriu care e si suffix
pentru i 1, m – 1 executa //pentru celelalte valori ale fct prefix
//consideram pi[i-1] cunoscuta si vrem sa determinam pi[i]
//cautam care este cel mai lung prefix la care putem adauga P[i]
//a.i. prin adaugarea caracterului prefixul sa fie si sufix
cat timp k > 0 si P[i] ≠ P[k] executa
k pi [k – 1] //prefixul prefixului
sf. cat timp
b) Varianta proprie
n lungime(T), m lungime (P)
pi determinare_fct_prefix
k 0 depl 0, i 0, déjà_testate 0
cat timp i < n executa
cat timp i<n si j<m si t[i] = p[j] executa //cat timp am potrivire
i i + 1, j j + 1, k k + 1 //numar si trec la urm. caracter
sf. cat timp
daca k = m atunci
scrie “deplasament:”, depl
sf. daca
Se dau doua siruri A si B formate din litere mici si mari ale alfabetului englez si din cifre. Se cere gasirea tuturor
aparitiilor sirului A ca subsecventa a sirului B.
Date de intrare
Fisierul de intrare strmatch.in contine 2 linii cu sirurile A, respectiv B.
Date de iesire
In fisierul de iesire strmatch.out se va afla pe prima linie numarul N de aparitii a sirului A in sirul B. Pe
urmatoarea linie se vor afla N numere care reprezinta pozitiile in care sirul A se potriveste peste sirul B, afisate in
ordine crescatoare. Pentru a evita fisierele de output foarte mari, in cazul in care N este mai mare decat 1000 se
vor afisa doar primele 1000 de pozitii. Sirurile sunt indexate de la 0.
Restrictii
Lungimea sirurilor A si B se afla in intervalul [1, 2 000 000]
Exemplu
strmatch.in strmatch.out
ABA 2
CABBCABABAB 5 7
Explicatie
CABBCABABAB
CABBCABABAB
Background
I want to tell you a story. Not entirely, but only the very beginning, because the ending of this story became a legend
of programming—as well as its heroes.
When computers were large, when trees were small, when the sun shined brighter… Once upon a time there were
Three Programmers. I doubt whether they participated in any programming contests, because there were no
contests at that ancient time. There was neither ACM ICPC nor Timus Online Judge. But there were Three
Programmers.
Problem
One day Three Programmers invented an amusing game to train memory and mental faculties. The First
Programmer thought out a string S which was N characters long and passed it to the Second and the Third
Programmers. The Second Programmer executed X (0 ≤ X < N) successive cycle shifts (a cycle shift is a transfer of the
last character of the string to the beginning of this string) with this string. As a result of these operations a string T
was produced, and the Second Programmer passed it to the Third Programmer. A task of the Third Programmer was
to find the number X or make sure that the Second Programmer was mistaken, because the string T could not be
produced from the string S via cycle shifts.
Input
The first line contains the integer number N (1 ≤ N ≤ 250000). The second line contains the string S. The third line
contains the string T. Each string has length N and may contain any ASCII characters with codes from 33 to 255.
Output
If the string T can be produced from the string S via cycle shifts you should output the desired number X, otherwise
you should output “−1”. If the problem has several solutions, you may output any of them.
Sample
input output
11 9
abracadabra
racadabraab
Input
The first input line contains S1 (it may consist only of the Latin letters). It’s guaranteed that the length of S1 doesn’t
exceed 10000 symbols.
Output
S1S2.
Samples
input output
No NoN
OnLine OnLineniLnO
AbabaAab AbabaAababA
Given two strings a and b we define a * b to be their concatenation. For example, if a = `abc' and b = `def'
then a * b = `abcdef'. If we think of concatenation as multiplication, exponentiation by a non-negative
integer is defined in the normal way: a0 = “” (the empty string) and a(n+1) = a * (an).
Input
Each test case is a line of input representing s, a string of printable characters. The length of s will be at
least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.
Output
For each s you should print the largest n such that s = an for some string a.
Sample Input
abcd
aaaa
ababab
.
Sample Output
1
4
3