Algoritmo KMP detallado
Primero explique qué algoritmo KMP:
El problema que debe resolver el algoritmo KMP es ubicar el patrón en la cadena (también llamada cadena principal). En pocas palabras, es la búsqueda de palabras clave que solemos decir. La cadena del patrón es la palabra clave (llamada P en el siguiente), si aparece en una cadena principal (llamada T en el siguiente), devuelve su posición específica; de lo contrario, devuelve -1 (medio de uso común)
Sobre la solución de este tipo de problema
- Método de fuerza bruta, complejidad temporal O ( N ∗ MN * Mnorte∗M ) (N es la longitud de la cadena principal, M es la longitud de la cadena del patrón), la cadena del patrón intenta hacer coincidir cada posición de la cadena principal hasta que la coincidencia es exitosa.
Por ejemplo:
cuando dos cadenas coinciden, el La cadena P comienza desde la cadena principal T El primer carácter comienza a coincidir y la posición roja es la posición donde el primer carácter no coincide. En este momento, el subíndice del carácter no
coincidentees i = j = 3. Lasiguiente coincidencia es que P comienza desde el subíndice 0 y T desde el subíndice 1 para coincidir, y luego repite este proceso.
Este método es demasiado violento, por lo que tenemos para introducir un método más rápido, elalgoritmo KMP - Complejidad de tiempo del algoritmo KMP O ( NNN ) La longitud de la cadena principal de N está
de acuerdo con el pensamiento normal. Para la coincidencia en la figura anterior, cuando ocurre una falta de coincidencia por primera vez, es natural pensar en la a en la cadena P y el subíndice 3 en la cadena T, es decir, caracteres coincidentes, consulte la figura
, es decir, la cadena del subíndice T i constante, la cadena P j se vuelve cero, es decir, la ventajacon esta coincidencia parcial tiene información válida, el puntero i no se detiene modificando el puntero j, por lo que que el patrón de cadena Intente moverse a una ubicación válida tanto como sea posible.
Veamos un conjunto de datos nuevamente.
Cuando T y P no coinciden en el subíndice 3, de acuerdo con lo anterior, i no se mueve, y la cadena P se mueve a la posición válida. La próxima vez que comience la comparación, el posición es j = 2.
De hecho, esto es como un proceso de empuje: laposición de j está determinada porel valor del sufijo de prefijo común más largo en la cadenaantesdeldesajuste entre P y T.
Primero, explica el prefijo y el sufijo. Toma la cadena como ejemplo. El
prefijo son todas las subcadenas consecutivas que contienen el primer carácter, pero no el último , como se muestra en la figura siguiente. El
sufijo es el que contiene el último carácter y no incluye el primero Todas las subcadenas consecutivas de caracteres
Aquí quiero encontrar una siguiente matriz para la cadena de patrón , la siguiente [i] representa el valor del sufijo de prefijo común más largo de los primeros caracteres i-1. Regulaciones artificiales next [0] = - 1, next [1] = 0;
- Porque cuando solo hay un carácter, no hay ningún carácter antes, por lo que no tiene sentido.
- Cuando hay dos caracteres, tome la cadena P anterior como ejemplo, el siguiente [1] es encontrar el valor del sufijo de prefijo común más largo de a antes de b, pero debido a que solo hay un carácter, el prefijo no incluye el último carácter y El sufijo no contiene el primer carácter, contradictorio, por lo que el valor es 0.
Para next [6], el prefijo y sufijo común más largo del abcabc frontal es abc, entonces next [6] = 3
Cómo resolver el siguiente arreglo
Empiece con el siguiente [2] Como se mencionó anteriormente, las posiciones 0 y 1 son valores especificados artificialmente. A continuación se muestra el método de solución del siguiente [i] (i> = 2).
- Primero, se debe especificar aquí un valor de k El valor de k representa el valor del siguiente [i-1], que es el valor del prefijo y sufijo común más largo en los primeros i-2 caracteres.
- Al resolver la siguiente [i], es necesario comparar si el carácter i-1º y el carácter k son iguales
- Cuando es igual, siguiente [i] = siguiente [i-1] +1;
- De lo contrario, k = siguiente [k], hasta que k = 0;
Por ejemplo:
valor inicial k = 0; nex [0] = - 1, siguiente [1] = 0; cuando
i = 2, p [1]! = P [k] (k = 0) significa b! = A
k = 0 // Es decir, ha llegado al final y aún no se ha emparejado. Porque k == 0, sea next [2] = 0; cuando
i = 3, p [2]! = P [k] (k = 0), porque k = = 0, por lo que sigue [3] = 0, cuando
i = 4 al final , p [3] == p [k] (k = 0), así que sigue [4 ] = ++ k; Es decir, siguiente [4] = 1; cuando
i = 5, p [4] = p [k] (k = 1), entonces siguiente [5] = ++ k; es decir, siguiente [5 ] = 2; lo
mismo Obtener siguiente [6] = 3
Pero solo me enteré después de ejecutarlo nuevamente. . . El uso de k = next [k] no se usa en este ejemplo. Luego voy a modificar la cadena P para que c con el subíndice 5 se convierta en a. Cuando
i = 6, k = 2, p [6]! = P [2], k = next [k], es decir k = 0
p [0] == p [6], entonces siguiente [6] = ++ k = 1;
Puede dividir P en dos partes y mirar la
siguiente matriz.
Lo siguiente es la parte del algoritmo KMP
- Ingrese dos cadenas s1, s2 (s1 es la cadena principal, s2 es la cadena del patrón)
- Obtenga la siguiente matriz de s2
- Defina dos punteros i1 e i2 para representar la posición de s1 y la posición de s2 respectivamente.
- Cuando s1 [i1] == s2 [i2], i1 ++, i2 ++
- De lo contrario, i2 = next [i2]
- Cuando i2 se mueve a 0, es decir, siguiente [i2] == - 1, i1 ++ coincide con el primero de la cadena de patrón y no coincide, y solo puede coincidir con el siguiente de la cadena principal.
- Finalmente, juzgue si i2 es igual a la longitud de s2, que es igual a devolver i1-i2; de lo contrario, devolver -1
Por ejemplo,
se ha calculado la siguiente matriz de cadena P, y las dos cadenas son diferentes cuando i1 = i2 = 6. En este momento, i1 no se mueve, i2 = siguiente [6] = 3. Como se muestra en la figura siguiente
, la coincidencia puede realizarse correctamente y devolver i1 -i2 = 3.
A continuación se muestra el código ()
Encuentra la siguiente matriz
void get_next()
{
Next[0]=-1;
Next[1]=0;
int i=2,k=0;//i是模式串的起始位置,即从第三个字符开始匹配,k是i-1个字符要匹配的位置
int len=s2.size();
while(i<len)
{
if(s2[i-1]==s2[k])//如果i-1和k相等,i后移准备匹配下一个位置,k后移
Next[i++]=++k;
else if(k>0)//没有匹配成功,k移动到next[k]的位置
k=Next[k];
else
Next[i++]=0;//移动到头了,next[i]只能为0了
}
}
km²
int kmp()
{
int i1=0,i2=0;
int len1=s1.size();
int len2=s2.size();
get_next();//获得Next数组
while(i1<len1&&i2<len2)//i1没到头,i2也没到头
{
if(s1[i1]==s2[i2])//相等就齐头并进
{
i1++;
i2++;
}
else if(next[i2]==-1)//模式串到头都没有和主串能匹配的字符,主串往后移
i1++;
else
i2=next[i2];//匹配不成功,i2移动
}
return i2==len2?i1-i2:-1;//i2到头证明匹配成功,否则返回-1
}
Pregunta de plantilla: HDU-1711
Pit: Este es un número, no un carácter, use una matriz de enteros para recibir el
código AC
#include<iostream>
#include<cstdio>
#include<string.h>
#include<queue>
#include<cmath>
#include<fstream>
using namespace std;
int Next[200005];
int s1[1000005];
int s2[1000005];
int a,b;
void get_next()
{
Next[0]=-1;
Next[1]=0;
int i=2,k=0;//i是模式串的起始位置,即从第三个字符开始匹配,k是i-1个字符要匹配的位置
int len=b;
while(i<len)
{
if(s2[i-1]==s2[k])//如果i-1和k相等,i后移准备匹配下一个位置,k后移
Next[i++]=++k;
else if(k>0)//没有匹配成功,k移动到next[k]的位置
k=Next[k];
else
Next[i++]=0;//移动到头了,next[i]只能为0了
}
}
int kmp()
{
int i1=0,i2=0;
get_next();
int len1=a;
int len2=b;
while(i2<len2&&i1<len1)//i1没到头,i2也没到头
{
if(s1[i1]==s2[i2])//相等就齐头并进
{
i1++;
i2++;
}
else if(Next[i2]==-1)//模式串到头都没有和主串能匹配的字符,主串往后移
i1++;
else
i2=Next[i2];//匹配不成功,i2移动
}
return i2==len2?i1-i2:-1;//i2到头证明匹配成功,否则返回-1
}
int main(void)
{
int t;
cin>>t;
while(t--)
{
//memset(Next,0,sizeof(Next));
int ans=kmp();
if(ans!=-1)
cout<<ans+1<<endl;
else
cout<<ans<<endl;
}
return 0;
}
Punto de
pozo de Logu P3375 : la siguiente matriz no contiene el valor de sufijo de prefijo más largo de los primeros n-1 caracteres, por lo que agrego un carácter inútil al principio y luego genera la siguiente matriz de 1 al generar.
Código de CA
#include<iostream>
#include<cstdio>
#include<string.h>
#include<queue>
#include<cmath>
using namespace std;
int next[2000005];
string s1,s2;
void get_next()
{
next[0]=-1;
next[1]=0;
int i=2,k=0;//i是模式串的起始位置,即从第三个字符开始匹配,k是i-1个字符要匹配的位置
int len=s2.size();
while(i<len)
{
if(s2[i-1]==s2[k])//如果i-1和k相等,i后移准备匹配下一个位置,k后移
next[i++]=++k;
else if(k>0)//没有匹配成功,k移动到next[k]的位置
k=next[k];
else
next[i++]=0;//移动到头了,next[i]只能为0了
}
}
int kmp()
{
int i1=0,i2=0;
get_next();
s2=s2.substr(0,s2.size()-1);
int len1=s1.size();
int len2=s2.size();
while(i1<len1)//i1没到头,i2也没到头
{
if(s1[i1]==s2[i2])//相等就齐头并进
{
i1++;
i2++;
}
else if(next[i2]==-1)//模式串到头都没有和主串能匹配的字符,主串往后移
i1++;
else
i2=next[i2];//匹配不成功,i2移动
if(i2==len2)
{
printf("%d\n",i1-i2+1);
i2=next[i2]; //再次匹配
i1--;
}
}
//return i2==len2?i1-i2:-1;//i2到头证明匹配成功,否则返回-1
}
int main(void)
{
cin>>s1>>s2;
s2+="$";
kmp();
next[0]++;
int len=s2.size();
for(int i=1;i<=len;i++)
{
printf("%d ",next[i]);
}
return 0;
}
Lo escribí toda la tarde, pero está terminado. Por favor, apúnteme si lo ha visto, gracias