Explicação detalhada do algoritmo KMP
Sabemos que o algoritmo BF é um método de força bruta, que exige tempo e esforço, então o que devemos fazer? Os três grandes deuses de DEKnuth, J, H, Morris e VRPratt criaram um algoritmo de correspondência rápida para nós - o algoritmo KMP. O núcleo desse algoritmo é que ele reduz o processo de retrocesso do ponteiro da string principal e melhora muito nossa correspondência. Rapidez.
O retrocesso do ponteiro da string principal mencionado acima, o que é isso? Deixe-me falar sobre as etapas de implementação do KMP.
1. Passos
- A obtenção do próximo valor da string principal
ocorre porque o KMP calculou o próximo valor da string principal antes da correspondência, de modo que o retrocesso do ponteiro de BF é reduzido. Para dar uma analogia:
主串:ababbbab
子串:abb
第一轮匹配:匹配到了第一个字符
ababbbab
a
第二轮匹配:匹配到了第二个字符
ababbbab
ab
第三轮匹配:匹配失败
匹配失败之后BF算法是这样的,从主串第二个字符又开始匹配,这就较做主串指针回溯。
ababbbab
abb
O código a seguir é para o próximo [] da string principal
void getnext() {
next[0] = -1;
int i = 0, j = -1;
int len = strlen(T);
while(i < len) {
if(j == -1 || T[i] == T[j])
next[++i] = ++j;
else
j = next[j];
}
}
O objetivo do próximo passo é descobrir se a substring na frente do caractere que não corresponde tem o mesmo prefixo e sufixo. Se houver, pule-o diretamente. Aqui está uma pequena evasão. Apresentarei um captura de tela em um momento. Portanto, o algoritmo KMP evita o problema de retrocesso do ponteiro.
Para simplificar, o algoritmo de backtracking também é conhecido como "heurística". Ao resolver o problema, cada passo que você dá é uma atitude de tentativa. Se você achar que a escolha atual não é a melhor, ou se continuar assim, definitivamente não alcançará seu objetivo, você deve imediatamente voltar e escolher novamente. Este método de voltar e voltar quando falha é o algoritmo de retrocesso.
Fazer uma combinação
bool KMP() {
getnext();
int len1 = strlen(T);
int len2 = strlen(S);
int i = 0, j = 0; //i指向模式串T,j指向主串S
while(j < len2) {
if(T[i] == S[j]) {
i++;
j++;
if(i == len2) {
return true;
}
} else {
i = next[i];
if(i == -1) {
j++;i++;
}
}
}
return false;
}
Não fale bobagem, apenas vá para a foto. Mostre a todos o processo do código acima
Processo específico:
Você pode ver as três fotos acima. As cinco primeiras são correspondidas, mas quando a sexta não é correspondida, o que devo fazer? i = next[i]
Essa sintaxe é usada para fazer a substring apontar para B na quarta imagem e, em seguida, iniciar o emparelhamento a partir de B.
- Código
#include <iostream>
#include<cstring>
#include <string>
typedef long long ll;
using namespace std;
bool KMP(char *T,char*S) {
int next[100];
next[0] = -1;
int i = 0, j = -1;
int len = strlen(T);
while(i < len) {
if(j == -1 || T[i] == T[j])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];
}
}
int len1 = strlen(T);
int len2 = strlen(S);
int i_ = 0, j_ = 0; //i指向模式串T,j指向主串S
while(j_ < len2) {
if(T[i_] == S[j_]) {
i_++;
j_++;
if(i_ == len2) {
return true;
}
} else {
i_ = next[i_];
if(i_ == -1) {
j_++;i_++;
}
}
}
return false;
}
int main()
{
char a[] = "ABBABBABAB";
char b[] = "ABBAB";
bool m = KMP(a,b);
printf("%d\n",m);
return 0;
}