Лекция 15 Поиск подстрок

21
Анализ комбинаторных алгоритмов Лекция № 15 Поиск подстрок.

Transcript of Лекция 15 Поиск подстрок

Page 1: Лекция 15 Поиск подстрок

Анализ комбинаторных алгоритмов

Лекция № 15Поиск подстрок.

Page 2: Лекция 15 Поиск подстрок

Задача поиска подстрок

Строками (или словами) называют массивы состоящие из символов некоторого конечного алфавита Σ.

Пусть даны две строки: текст T[1..n] длины n и образец P[1..m] длины m<n.

Говорят, что образец P входит со сдвигом s (или входит с позиции s+1) в текст T, если 0 ≤ s ≤ n-m и верно T[s+1..s+m] = P[1..m].

Page 3: Лекция 15 Поиск подстрок

Задача поиска подстрок

Если P входит в T со сдвигом s,то говорят, что s – допустимый сдвиг.

В противном случае s называют недопустимым сдвигом.

Задача поиска подстрок состоит в нахождении всех допустимых сдвигов для заданных текста T и образца P.

Page 4: Лекция 15 Поиск подстрок

Обозначения и терминология

Через Σ* обозначается множество всех конечных строк в алфавите Σ, включая пустую строку.

Соединение (конкатенация) строк x и у обознается xy.

Говорят, что w префикс x (w x), если x=wy, для некоторого y из Σ*.

Говорят, что w суффикс x (w x), если x=yw, для некоторого y из Σ*.

Page 5: Лекция 15 Поиск подстрок

Обозначения и терминология

ТеоремаПусть x, y, z – строки, для которых верно x z, y z. Тогда x y, если |x|<|y|, y x, если |y|<|x| и y=x, если |y|=|x|

Page 6: Лекция 15 Поиск подстрок

Простейший алгоритм

void StringMatcher(T,P,n,m){ for(s=0; s<=n-m; s++){ b = true; for(i=1; i<=m; i++) b = b & (T[s+i]==P[i]); if (b) print(“подстрока входит со сдвигом”, s); }}

a c a a b c

a a b

a c a a b c

a a b

a c a a b c

a a b

Page 7: Лекция 15 Поиск подстрок

Алгоритм Рабина-Карпа

Алгоритм Рабина-Крапа предполагает, что Σ={0,1,2…d-1}

Строкам T, P и всем подстрокам T длины s можно сопоставить числа t, p, ts.

Эти числа можно найти за время O(m), где m – длина строки, используя схему Горнера:p = P[m]+d(P[m-1]+d(P[m-2]+…+d P[1])…)

Page 8: Лекция 15 Поиск подстрок

Алгоритм Рабина-Карпа

Числа t1,t2,…tn-m можно вычислить за время O(n-m), поскольку число ts+1 можно вычислить за O(1) считая известным ts

ts+1 = d(ts – dm-1 T[s+1] ) + T[s+m+1]

Для определения вхождения достаточно сравнить числа p и ts.

Для того чтобы уйти от операций с большими числами используют арифметику по модулю q (простое число)

Page 9: Лекция 15 Поиск подстрок

Алгоритм Рабина-Карпа

void RabinKarpMatcher(T,P,n,m,d,q){ h = ModExp(d,m-1,q); p = 0; t[0]=0; for(i=1; i<=n; i++){ p = (d*p+P[i]) % q; t[0]= (d*t[0]+T[i]) % q; } for(s=0; s<=n-m; s++){ if(p==t[s]){ b = true; for(i=1; i<=m; i++) b = b & (T[s+i]==P[i]); if(b){print(“подстрока входит со сдвигом”, s);} } if (s<n-m) t[s+1] = (d*(t[s]-T[s+1]*h)+T[s+m-1])%q; }}

Page 10: Лекция 15 Поиск подстрок

Алгоритм Рабина-Карпа

2 3 5 9 0 2 3 1 4 1 5 2 6 7 3 9 9 2 1

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

Mod 13

Page 11: Лекция 15 Поиск подстрок

Конечные автоматы

Конечный детерминированный автомат (F-схема) – определяется пятеркой чисел M=(Q,q0,A,Σ,δ), где:Q – конечное множество состоянийq0 – начальное состояниеA – множество допускающих

состоянийΣ – конечный входной алфавитδ – функция переходов Q x Σ.

Page 12: Лекция 15 Поиск подстрок

Конечные автоматы

Конечный автомат распознающий образец P в тексте строится следующим образом: Определяется суффикс-функция σ, ставящая в

соответствие строке x максимальную длину суффикса x являющегося префиксом P.

Множество состояний Q = {0,1,…,m}. Начальное состояние q0 = 0, единственное разрешающее состояние m

Функция переходов определена как δ(q,a) = σ(Pq,a)

Page 13: Лекция 15 Поиск подстрок

Конечные автоматы

P = «ababaca»

0 1 2 3 4 5 6 7a

a

b aa

b aa a

bb

c a

0 1 2 3 4 5 6 7a 1 1 3 1 5 1 7 1b 0 2 0 4 0 4 0 2c 0 0 0 0 0 6 0 0

Page 14: Лекция 15 Поиск подстрок

Конечные автоматы

void FiniteAutomatonMatcher(T,n,m){ q = 0; ComputeTF(P,m,sigma,l); for(i=0; i<=n; i++){ q = TF[q, T[i]]; if (q == m) print(“подстрока входит со сдвигом”, i-m); }}void ComputeTF(P,m,sigma,l){ for(q=0; q<=m; q++){ for(i=1; i<=l; i++){ k = min(m+1,q+2); do{k--;}while(SuffixFunc(P,k,P,q,a)); // пока Pk – суффикс Pq+a TF[q,a]=k; } }}

Page 15: Лекция 15 Поиск подстрок

Алгоритм Кнута-Морриса-Пратта

b a c c a b a b a b a c a b a

a b a b a c a

b a c c a b a b a b a c a b a

a b a b a c a

q

k

s

s`

s` = s + (q-k)

Page 16: Лекция 15 Поиск подстрок

Алгоритм Кнута-Морриса-Пратта

Алгоритм Кнута-Морриса-Пратта работает за линейное время O(n+m)

Алгоритм использует понятие префикс-функции.

Префикс-функция π(q) – длина наиболь-шего префикса P, являющегося собст-венным суффиксом Pq: π(q) = max{k: k<q и Pk Pq}

Page 17: Лекция 15 Поиск подстрок

Алгоритм Кнута-Морриса-Пратта

void KMPMatcher(T,P,n,m){ PF = ComputePrefixFunc(P,m); q=0; for(i=0; i<=n; i++){ while((q>0)&&(P[q+1]!=T[i])) q = PF[q]; if(P[q+1]==T[i]) q++; if(q==m) {print(“подстрока входит со сдвигом”, i-m); q = PF[q]; } }}void ComputePrefixFunc(P,m){ PF[1]=0; k=0; for(q=2;q<=m;q++){ while((k>0)&&(P[k+1]!=P[q])) k = PF[k]; if(P[k+1]=P[q]) k++; PF[q] = k; }}

Page 18: Лекция 15 Поиск подстрок

Алгоритм Бойера-Мура

w r i t t e n _ n o t i c e _ t h a t

r e m i n i s c e n c e

Стоп символ Безопасный суффикс

s

w r i t t e n _ n o t i c e _ t h a t

r e m i n i s c e n c es+4

w r i t t e n _ n o t i c e _ t h a t

r e m i n i s c e n c es+3

Page 19: Лекция 15 Поиск подстрок

Алгоритм Бойера-Мура

void ComputeLastOccFunc(P,m,Sigma,lambda){ for(i=0; i<Sigma->size; i++) Lambda[i]=0; for(j=1; j<=m; m++){ Lambda[P[j]]=j; }}

Эвристика стоп-символа предлагает сдвинуть образец на такое расстояние, чтобы стоп-символ в тексте оказался на против крайнего правого вхождения этого символа в образец.

Page 20: Лекция 15 Поиск подстрок

Алгоритм Бойера-Мура

void ComputeGoodSuffixFunc(P,m,gamma){ pi = ComputePrefixFunc(P,m) P1 = ReverseString(P); pi1= ComputePrefixFunc(P1,m); for(j=0; j<=m; j++) gamma[j]= m-pi[m]; for(i=1; i<=m; i++){ j = m – pi1[i]; if(gamma[j]>i-pi1[i]) gamma[j]=i-pi1[i]; }}

Эвристика безопасного суффикса предлагает сдвинуть образец вправо так, чтобы ближайшее (справа налево) вхождение безопасного суффикса в образец оказалось напротив суффикса в тексте.

Page 21: Лекция 15 Поиск подстрок

Алгоритм Бойера-Мура

void BoyerMooreMatcher(T,P,Sigma,n,m){ ComputeLastOccFunc(P,m,Sigma,lambda); ComputeGoodSuffixFunc(P,m,gamma); s =0 while(s<=n-m){ j = m; while((j>0)&&(P[j]=T[s+i])) j--; if(j=0){ print(“подстрока входит со сдвигом”,s); s = s+gamma[0]; } else s = s + max(gamma[j],j-lambda[T[s+j]]); }}