Algoritmo KMP (coincidencia de cadenas) (AcWing)

El algoritmo KMP se usa a menudo para la coincidencia de cadenas. Antes de presentar el algoritmo KMP para la coincidencia, primero presente cómo hacer coincidir violentamente las cadenas.

 Para dos cadenas, use dos punteros para comparar a su vez, el código:

for (int i = 1; i <= n; i ++ )
{
    bool flag = true;
    for (int j = 1; j <= m; j ++ )
    {
        if (s[i + j - 1] != p[j])
        {
            flag=false;
            break;
        }
    }
}

Si no coincide, es equivalente a mover la cadena corta hacia la derecha para continuar con la coincidencia, pero la eficiencia de la comparación secuencial es muy baja.

 KMP utiliza la información efectiva de cadenas ya coincidentes para reducir las coincidencias repetidas.

 Por ejemplo, en la figura, cuando la cadena larga y la cadena corta se emparejan con éxito durante un cierto intervalo, la coincidencia en las posiciones i y j+1 de la figura falla. De acuerdo con el pensamiento convencional, necesitamos mover la cadena corta retroceda una posición y continúe para comenzar la coincidencia nuevamente. , pero kmp debe hacer un buen uso de la información coincidente para reducir el número de coincidencias, es decir, sea j=ne[j], comience la coincidencia desde la posición de ne[ j], porque la parte que dibujamos con la línea negra en la figura es en realidad igual a Es efectivo, por lo que no necesitamos hacer coincidir esta parte, entonces, ¿cómo encontrar esta matriz ne[j]?

Aquí hay un concepto para introducir, es decir, prefijo y sufijo :

 Ahora que conocemos la idea, ¿cómo implementarla con código?

Ideas:

 código:

	for (int i = 2, j = 0; i <= m; i++)
	{
		while (j && str1[i] != str1[j + 1])j = ne[j];
		if (str1[j + 1] == str1[i])j++;
	    ne[i] = j;
	}

A continuación, simulemos una muestra:

 tema:

Código CA:

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1000010, M = 10010;
char str[N], str1[M];
int ne[N], n, m;

int main(void)
{
	cin >>(str + 1) >>(str1 + 1);
	int n = strlen(str+1), m = strlen(str1+1);
	//获取ne数组
	for (int i = 2, j = 0; i <= m; i++)
	{
		while (j && str1[i] != str1[j + 1])j = ne[j];
		if (str1[j + 1] == str1[i])j++;
		ne[i] = j;
	}
	//开始匹配
	for (int i = 1, j = 0; i <= n; i++)
	{
		while (j && str1[j + 1] != str[i])j = ne[j];
		if (str[i] == str1[j + 1])j++;
		if (j == m)
		{
			printf("%d\n", i - m+1);
		}
	}
	for (int i = 1; i <= m; i++)
	{
		printf("%d ", ne[i]);
	}
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/AkieMo/article/details/128434277
Recomendado
Clasificación