36
Algoritmo KMP (Knuth-Morris- Pratt) Curso de Maratona de Programação ICT-Unifesp - SJC

Algoritmo de Knuth-Morris-Pratt - KMP

Embed Size (px)

Citation preview

Page 1: Algoritmo de Knuth-Morris-Pratt - KMP

Algoritmo KMP(Knuth-Morris-Pratt)

Curso de Maratona de ProgramaçãoICT-Unifesp - SJC

Page 2: Algoritmo de Knuth-Morris-Pratt - KMP

2

KMP• Para que serve?• Saber se uma string é substring de outra.• String searching algorithm.

• É legal?• Sim, você escreve pouco (código pequeno) e é eficiente!

• Vídeo-aula utilizando esses slides:• https://youtu.be/VxcrVqoi_k8

Page 3: Algoritmo de Knuth-Morris-Pratt - KMP

3

KMP• Ideia do algoritmo:• Procura uma palavra (padrão) P dentro de um texto T.• Quando aparece uma diferença (mismatch), a palavra tem em si a informação

necessária para determinar onde começar a próxima comparação, ou seja, um mistmach consiste em caracteres que já conhecemos porque eles estão na palavra/padrão (isso evita retroceder pelos caracteres já conhecidos).• Pense: considerando um algoritmo de força bruta, quando ocorre uma

diferença entre T[i] e P[j], não seria possível fazer um deslocamento maior de P para a direita evitando comparações redundantes?

Page 4: Algoritmo de Knuth-Morris-Pratt - KMP

4

KMP• Ideia do algoritmo:

A B A A B X

A B A A B A

i

j

T

P

o maior prefixo que é sufixo é o AB

Page 5: Algoritmo de Knuth-Morris-Pratt - KMP

5

KMP• T[i] != P[j]

A B A A B X

A B A A B A

i

j

T

P

pode-se recomeçar a partir daquiessas comparações não precisam ser refeitas

Page 6: Algoritmo de Knuth-Morris-Pratt - KMP

6

KMP• Exemplo:• texto = "eu gosto de c++"• palavra: "gosto"• A palavra "gosto" foi encontrada na posição 3 (indexando a partir do 0).

Page 7: Algoritmo de Knuth-Morris-Pratt - KMP

7

KMP• Aplicação:• Quando você utiliza um editor de sua preferência e quer buscar uma string

em um arquivo, esses tipos de algoritmos são utilizados para exibir os resultados da busca.

Page 8: Algoritmo de Knuth-Morris-Pratt - KMP

8

KMP• Complexidade:• A complexidade no pior caso é O(n) onde “n” é o tamanho do texto em que a

palavra será buscada.• Um algoritmo ruim teria complexidade O(n * m) onde “n” seria o tamanho do

texto e “m” o tamanho da palavra.

• Duas etapas:• prefix function• string matching

Page 9: Algoritmo de Knuth-Morris-Pratt - KMP

9

KMP• Prefix function:• KMP faz um pré-processamento da palavra (padrão) e constrói um array

auxiliar (vou chamá-lo de “aux”) de tamanho “m” (mesmo tamanho da palavra).• O pré-processamento analisa todos os prefixos do padrão procurando pelo

maior sufixo destes prefixos que também seja prefixo. • O pré-processamento evita que um caractere seja reexaminado!• Exemplo: ABAB

• O maior sufixo que também é prefixo é o “AB” que termina na posição 1 (indexando a partir do 0) e também ocorre na posição 2.

Page 10: Algoritmo de Knuth-Morris-Pratt - KMP

10

KMP• Prefix function:• Ao final, teremos um array que conterá cada posição que gera um prefixo

para cada posição do padrão.• O pré-processamento é feito na palavra (padrão) para determinar se seus

prefixos aparecem como subsequências deles mesmos.• O array que iremos construir nessa fase chamaremos de “aux” de forma que:

• O tamanho do maior prefixo de aux[0..k] que é sufixo de aux[1..k].• Ou seja, é o tamanho do maior “começo” de aux[k] que também aparece no seu “fim”

sem condiderar ele mesmo.

Page 11: Algoritmo de Knuth-Morris-Pratt - KMP

11

KMP

Prefix function

Page 12: Algoritmo de Knuth-Morris-Pratt - KMP

12

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j i

0 1 2 3 4 5 6 7

0

A == B ? Não, coloca 0 na posição marcada por “i” e incrementa “i”

Page 13: Algoritmo de Knuth-Morris-Pratt - KMP

13

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j i

0 1 2 3 4 5 6 7

0 0

A == C ? Nãão, coloca 0 na posição marcada por “i” e incrementa “i”

Page 14: Algoritmo de Knuth-Morris-Pratt - KMP

14

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j i

0 1 2 3 4 5 6 7

0 0 0

A == D ? Nããão, coloca 0 na posição marcada por “i” e incrementa “i”

Page 15: Algoritmo de Knuth-Morris-Pratt - KMP

15

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j i

0 1 2 3 4 5 6 7

0 0 0 0

A == A ? Sim, incrementa “j”, guarda o valor de “j” na posição marcada por “i” e incrementa o “i”

Page 16: Algoritmo de Knuth-Morris-Pratt - KMP

16

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j i

0 1 2 3 4 5 6 7

0 0 0 0 1

B == B ? Simm, incrementa “j”, guarda o valor de “j” na posição marcada por “i” e incrementa o “i”

Page 17: Algoritmo de Knuth-Morris-Pratt - KMP

17

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j i

0 1 2 3 4 5 6 7

0 0 0 0 1 2

C == C ? Simmm, incrementa “j”, guarda o valor de “j” na posição marcada por “i” e incrementa o “i”

Page 18: Algoritmo de Knuth-Morris-Pratt - KMP

18

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j i

0 1 2 3 4 5 6 7

0 0 0 0 1 2 3

D == A ? Não, mas o j é diferente de 0, então podemos fazer: j = aux[j – 1],ou seja, j = 0, não incrementa o “i” e nem o “j’

Page 19: Algoritmo de Knuth-Morris-Pratt - KMP

19

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j i

0 1 2 3 4 5 6 7

0 0 0 0 1 2 3

Voltamos tudo de novo :(, calma, está terminando...A == A ? Sim, incrementa “j”, guarda o valor de “j” na posição marcada por “i” e incrementa o “i”

Page 20: Algoritmo de Knuth-Morris-Pratt - KMP

20

KMP• Considere a palavra: ABCDABCA

A B C D A B C A

j

0 1 2 3 4 5 6 7

0 0 0 0 1 2 3 1

i = 8, ou seja, não é menor do que o tamanhoda palavra ABCDABCA, portanto, chegamos ao fim da execução.

Page 21: Algoritmo de Knuth-Morris-Pratt - KMP

21

KMP• Algoritmo da fase de pré-processamento (prefix function):

substr = palavra = padrão

Page 22: Algoritmo de Knuth-Morris-Pratt - KMP

22

KMP

String matching

Page 23: Algoritmo de Knuth-Morris-Pratt - KMP

23

KMP• Vamos tentar identificar a palavra “CD”• Primeiro fazemos o pré-processamento construindo o vetor “aux”

para o padrão que se quer encontrar.

idx_substr -> índice da substring/palavra/padrãoidx_str -> índice da string/texto

idx_substr = idx_str = 0

C D

0 1

0 0

Page 24: Algoritmo de Knuth-Morris-Pratt - KMP

24

KMP• Vamos tentar identificar a palavra “CD”

C D

0 1

0 0

Critério de parada: idx_str < tam_str

Page 25: Algoritmo de Knuth-Morris-Pratt - KMP

25

KMP• Vamos tentar identificar a palavra “CD”

A B C D A B C A

Lembrando que idx_substr = 0 e idx_str = 0

substr[idx_substr] == str[idx_str] ? C == A ? Não (mismatch)

Page 26: Algoritmo de Knuth-Morris-Pratt - KMP

26

KMP• Vamos tentar identificar a palavra “CD”

A B C D A B C A

Lembrando que idx_substr = 0 e idx_str = 0

idx_substr == tam_substr ?0 == 2 ?

Não, ou seja, a palavra ainda não foi encontrada no texto.

Page 27: Algoritmo de Knuth-Morris-Pratt - KMP

27

KMP• Vamos tentar identificar a palavra “CD”

A B C D A B C A

Lembrando que idx_substr = 0 e idx_str = 0

// mismatches após idx_substr matches

idx_str < tam_str E substr[idx_substr] != str[idx_str] ?Ou seja, 0 < 8 E C != A ? Sim, então verificamos:

idx_substr != 0 ? Não, então idx_str = idx_str + 1 = 1

Page 28: Algoritmo de Knuth-Morris-Pratt - KMP

28

KMP• Vamos tentar identificar a palavra “CD”

A B C D A B C A

idx_substr = 0 e idx_str = 1

substr[idx_substr] == str[idx_str] ? C == B ? Não.idx_substr == tam_substr? 0 == 2 ? Não.

idx_str < tam_str E substr[idx_substr] != str[idx_str] ?1 < 8 E C != B ? Sim.

idx_substr != 0 ? Não, então idx_str = idx_str + 1 = 2

Page 29: Algoritmo de Knuth-Morris-Pratt - KMP

29

KMP• Vamos tentar identificar a palavra “CD”

A B C D A B C A

idx_substr = 0 e idx_str = 2

substr[idx_substr] == str[idx_str], C == C ?Sim, então incrementa idx_substr e idx_str em 1

Agora idx_substr = 1 e idx_str = 3

idx_substr == tam_substr ? 1 == 2 ? Não, ainda não encontramos o padrão.idx_str < tam_str E substr[idx_substr] != str[idx_str] ? Não, porque D == D!

Page 30: Algoritmo de Knuth-Morris-Pratt - KMP

30

KMP• Vamos tentar identificar a palavra “CD”

A B C D A B C A

idx_substr = 1 e idx_str = 3substr[idx_substr] == str[idx_str], D == D ?

Sim, então incrementa idx_substr e idx_str em 1

Agora idx_substr = 2 e idx_str = 4idx_substr == tam_substr ? 2 == 2 ?

Sim, então imprime que o padrão foi encontrado.

Page 31: Algoritmo de Knuth-Morris-Pratt - KMP

31

KMP• Vamos tentar identificar a palavra “CD”

A B C D A B C A

idx_substr = 2 e idx_str = 4

Após a impressão do padrão encontrado, é feito:idx_substr = aux[idx_substr – 1]

Aqui utilizamos o array que construímos no pré-processamento.idx_substr = aux[2 – 1] = aux[1] -> idx_substr = 0

Aqui não fez muita diferença, pois nosso padrão é apenas “CD”, o importante é que nessa parte tenta evitar comparações descenessárias fazendo uso do array “aux”.

C D

0 1

0 0

Page 32: Algoritmo de Knuth-Morris-Pratt - KMP

32

KMP• Vamos tentar identificar a palavra “CD”

A B C D A B C A

E assim sucessivamente, o algoritmo encontra todas as posições do padrão buscado no texto e de forma rápida: O(n)!

Page 33: Algoritmo de Knuth-Morris-Pratt - KMP

33

KMP• Algoritmo da etapa string matching:

Page 34: Algoritmo de Knuth-Morris-Pratt - KMP

34

KMP• Algoritmo:• https://goo.gl/ybXQqN• ou https://gist.github.com/marcoscastro/618bcfc9ec58e3b27661

• Implementação em C++:• https://goo.gl/g0mrcL• ou https://gist.github.com/marcoscastro/55cc08aef269d6d006d2

• Vídeo-aula:• https://youtu.be/VxcrVqoi_k8

Page 35: Algoritmo de Knuth-Morris-Pratt - KMP

35

Considerações sobre strings• Se eu tenho só duas strings e quero achar uma dentro da outra, o que

eu posso usar para otimizar?• Resposta: KMP.

• Se eu tenho várias strings e quero encontrar a ocorrência delas em uma única string, o que eu posso usar para otimizar?• Resposta: Suffix Tree ou Suffix Array.• Otimização: algoritmo de Ukkonen para construir a suffix tree.

• E a Trie (árvore de prefixo)?• Uma alternativa ao map.