notas de estudio de kmp (plantilla)

notas de estudio de kmp

Introduccion

El algoritmo de búsqueda de cadenas Knuth-Morris-Pratt (denominado algoritmo KMP
para abreviar ) se utiliza para la coincidencia de patrones de cadenas. En comparación con el algoritmo ingenuo, su complejidad temporal es O (n + m), donde n es la longitud de la cadena de texto ym es la longitud de la cadena del patrón.

Principio

kmp reduce las comparaciones repetitivas en el algoritmo ingenuo calculando la siguiente matriz de cadenas de patrones como ayuda.

La siguiente matriz representa el sufijo verdadero idéntico más largo de la cadena de patrón. Por ejemplo: en la cadena de patrón s = "ABABCD", su siguiente matriz es siguiente = [-1 0 0 1 2 0 0]. Donde siguiente [0] es -1, es para asegurarse de que no caerá en un bucle sin fin cuando el desajuste completo.

Supongamos que hay una cadena de texto t = "ABADDABABD". Comience con la posición 0 como punto de partida y haga coincidir t [0: 2] = "ABA", pero haga coincidir t [3] = 'D'! = S [3] = 'C'. La posición 1 se reinicia. Como se conoce por next [3] = 1, el sufijo más largo y verdadero antes de la posición 3 de la cadena s es 1, es decir s [0: 0] == s [2: 2]. Por lo tanto, puede coincidir directamente desde la posición 3 de la cadena de texto a la posición 1 de la cadena de patrón, es decir, la siguiente posición [3].

¿Cómo construir la siguiente matriz? Suponiendo que se ha construido la siguiente matriz, incluida la posición i, establezca j = siguiente [i]. Si s [i + 1] == s [j + 1], entonces obviamente siguiente [i + 1] = j + 1; de lo contrario, ya que s [0: siguiente [j]] tiene un prefijo verdadero y s [0: i -1] Los sufijos verdaderos son iguales, por lo que sea j = siguiente [j], si s [i + 1] == s [j + 1], luego siguiente [i] = j, de lo contrario, repita el proceso anterior hasta que j = siguiente [ 0] = -1 significa que no existe el mismo sufijo verdadero, luego siguiente [i] = 0.

Lograr

La pizarra es muy fácil de escribir.

//求next
int next[N];
void getnext(char *t) {
    int i = 0, j = -1;
    next[i] = j;
    while(s[i]) {
        if(j == -1 || s[i]  == s[j]) {
            i++;
            j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
}
void search(char *s, char *t) {
    int i = 0;
    int j = 0;
    while(s[i]) {
        if(j == -1 || s[i] == t[j]) {
            i++;
            j++;
            if(!s[j]) { //找到了
                //处理
                j = next[j]; //继续找。如果只找一次可以直接break
            }
        } else {
            j = next[j];
        }
    }
}

Solicitud

Además de combinar cadenas de patrones, también puede encontrar secciones de bucle, encontrar el sufijo más largo y el mismo, y así sucesivamente. Tema específico

Kmp extendido

Deje que la cadena de texto sea s (longitud n) y la cadena de patrón t (longitud m). Expandir kmp es buscar la matriz extendida. Donde la extensión [i] representa el prefijo idéntico más largo de t y s [i: n-1].

Porque cuando existe extender [i] == m, funciona como el algoritmo kmp, por lo que también se llama kmp extendido.

La búsqueda de la matriz extendida requiere la siguiente matriz como auxiliar. A continuación, [i] representa el prefijo idéntico más largo de t y t [i: m-1]. Suponiendo que se ha obtenido la siguiente matriz, lo siguiente encuentra la matriz extendida.

Sea p el límite más a la derecha que se puede alcanzar durante el proceso de correspondencia. Sea a la posición correspondiente a p, es decir, extienda [a] = p-a. Se supone que se ha obtenido la matriz extendida antes de i-1. Entonces primero, la posición de i debe ubicarse dentro del intervalo [a, p]. Entonces la posición i corresponde a la posición en la siguiente i-a. Hay dos situaciones:

  1. Si i + next [i-a] es menor que p, entonces extienda [i] = next [i-a];
  2. Si i + next [i-a] es mayor o igual que p, entonces simplemente expanda sobre la base de t [p-i]. Tenga en cuenta que es p-i en lugar de p-a, porque se basa en la extensión del prefijo. Luego actualice p y a.

Buscar la siguiente matriz es en realidad el proceso de preguntarse por la matriz extendida.

La pizarra es fácil de escribir.

int extend[N], next[N];
void getnext(char *t) {
    int a = 0, p = 0;
    int len = strlen(t);
    nt[a] = len;
    for(int i = 1; i < len; i++) {
        if(i >= p || i + nt[i - a] >= p) { 
            if(i >= p) p = i;
            while(p < len && t[p] == t[p - i]) p++;
            nt[i] = p - i;
            a = i;
        } else {
            nt[i] = nt[i - a];
        }
    }
}

void search(char *s, char *t) {
    int a = 0, p = 0;
    int n = strlen(s);
    int m = strlen(t);
    for(int i = 0; i < n; i++) {
        if(i >= p || i + nt[i - a] > p) { // i >= p 的作用:举个典型例子,S 和 T 无一字符相同
            if(i >= p) p = i;
            while(p < n && p - i < m && s[p] == t[p - i]) p++;
            extend[i] = p - i;
            a = i;
        } else {
            extend[i] = next[i - a];
        }
    }
}

Temas relacionados

kuangbin kmp 专题

扩展 kmp :
Mensaje de Clairewd
Periodo II
Cuenta la cadena

Referencia

https://oi-wiki.org/string/kmp/

Supongo que te gusta

Origin www.cnblogs.com/limil/p/12695071.html
Recomendado
Clasificación