Python implementa el algoritmo KMP

Entendido completamente

En el algoritmo de coincidencia de cadenas, el algoritmo KMP puede lograr una complejidad casi O(N), la clave es eliminar el retroceso del puntero principal, lo que puede ahorrar mucho tiempo.

Por ejemplo, si desea hacer coincidir abcdabcey hacer abcecoincidir, el algoritmo de fuerza bruta se muestra en la siguiente tabla, cada vez que necesita comparar 4 caracteres, un total de 5 veces.

un b C d un b C mi
1 un b C mi
2 un b C mi
3 un b C mi
4 un b C mi
un b C mi

Sin embargo, podemos ver de un vistazo que esto dno abceestá en absoluto, por lo que si podemos almacenar alguna otra información, tal vez podamos omitir esto de inmediato d.

un b C d un b C mi
1 un b C mi
un b C mi

Pero a veces no puedes saltar más, por ejemplo, si quieres abcabcabchacer coincidir cab, una mejor solución es más o menos la siguiente

un b C un b C un b C
1 C un b
C un b

Entonces, el quid de la pregunta es, ¿por qué el caso anterior se puede omitir directamente dy el caso siguiente solo se puede omitir exactamente dos?

Para resumir, encontramos dos reglas. Deje que txt sea un texto largo, necesita encontrar una cadena en txt, y deje que el carácter de la comparación actual sea ch, hay dos reglas simples

ch no está en str str saltar esta ch
ch pasa a ser str[0] str se transfiere a la posición de este ch

Entonces, si ch está en str, pero no en str[0], ¿qué se debe considerar?

Por supuesto, no se puede omitir directamente, porque puede haber secuencias repetidas en str, como la coincidencia abababcde ellos ababc, entonces la mejor solución debería ser

un b un b un b C
1 un b un b C
un b un b C

Es decir, para ababceste tipo de cadenas, debido a alas diferentes posiciones, cuando obtengamos una nueva a, se tomará una decisión diferente.

En la siguiente figura, el círculo representa la coincidencia actual, la flecha representa un nuevo carácter y la flecha apunta a la siguiente posición de salto. Un signo de exclamación significa que no es un carácter determinado.

b
a
b
c
!a
!b
a
!a!c
a
ab
aba
abab
ababc

Ver aquí no es un sentimiento de comprensión, esta es la llamada máquina de estado, y el proceso de construcción de esta máquina de estado no tiene nada que ver con txt. En otras palabras, solo haga una auto-coincidencia en str antes de hacer coincidir txt, y puede obtener una máquina de estado como esta.

El estado en la máquina de estados en realidad representa la posición del puntero en la cadena que se va a emparejar. Volver a a significa que el puntero apunta a 0; al avanzar, el puntero aumenta en 1; cuando abab recibe una a y vuelve al paso de aba, significa que el puntero retrocede de 5 a 3, como se muestra en la siguiente tabla.

un lejos aba abab ababc
un 0 0 0 3
b 0 0 0 0
C 0 0 0 0 éxito
otro 0 0 0 0

¿Te diste cuenta de repente de que la llamada máquina de estado es en realidad una matriz?

Lo siguiente que tenemos que hacer es generar esta matriz de estado.

implementación aproximada

O considere encontrar str de txt, y el primer paso es establecer la matriz de estado de str

test = "ababcdabadc"    #python中str是关键字,所以改个名
length = len(test)
#创建用于存储状态的字典
status = {
    
    s:[0 for _ in range(length)] for s in set(test)}
for ch in status:
    for i in range(length):
        for j in range(i+1):
            if test[i-j:i]+ch == test[0:j+1]:
                status[ch][i] = j+1

conseguir

b [0, 2, 0, 4, 0, 0, 0, 8, 0, 4, 0]
d [0, 0, 0, 0, 0, 6, 0, 0, 0, 10, 0]
c [0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 11]
a [1, 1, 3, 1, 3, 1, 7, 1, 9, 1, 1]

Para una cadena ababcdabadc, el puntero inicial es 0. Si hay uno en este momento a, el puntero saltará a él a[0]=1, indicando ael estado en el que se encuentra en este momento, si hay otro en este momento b, el puntero saltará a b[1]=2, indicando abel estado en el que se encuentra en ese momento, etc.

Después de hacer la matriz de estado de str, es muy conveniente realizar una comparación de cadenas.

txt = "ababcdabasdcdasdfababcdabadc"
test = "ababcdabadc" 
KMP(txt,test)

def KMP(txt,test):
    status = setStatus(test)
    length = len(test)
    keySet = set(status.keys())
    match = []
    j = 0
    for i in range(len(txt)):
        s = txt[i]
        j = status[s][j] if s in keySet else 0
        if j==length:
            match.append(i-length+1)
    return match

def setStatus(test):
    length = len(test)
    #创建用于存储状态的字典
    status = {
    
    s:[0 for _ in range(length)] for s in set(test)}
    for ch in status:
        for i in range(length):
            for j in range(i+1):
                if test[i-j:i]+ch == test[0:j+1]:
                    status[ch][i] = j+1
    return status

Optimización de la matriz de coincidencia

En general, aaaaaaala matriz de coincidencias para cadenas que no sean la enloquecedora es escasa, lo que significa que hacemos muchas comparaciones inútiles. Por lo tanto, el proceso de solución de su matriz de coincidencia se puede optimizar aproximadamente, al menos se puede eliminar el bucle más externo.

def setStatus(test):
    length = len(test)
    #创建用于存储状态的字典
    status = {
    
    s:[0 for _ in range(length)] for s in set(test)}
    for i in range(length):
        for j in range(i+1):
            if test[i-j:i] == test[0:j]:
                ch = test[j]
                status[ch][i] = j+1
    return status

Ahora solo quedan dos capas de bucles, lo que parece refrescante, pero a las personas que comen melones que no conocen la verdad todavía les importa O ( N 2 ) O(N^2)O ( mujeres )2 )complejidad. Para ser más refrescantes, examinemos las características de la matriz coincidente

b [0, 2, 0, 4, 0, 0, 0, 8, 0, 4, 0]
d [0, 0, 0, 0, 0, 6, 0, 0, 0, 10, 0]
c [0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 11]
a [1, 1, 3, 1, 3, 1, 7, 1, 9, 1, 1]

Primero, la mayoría de los valores distintos de cero se incrementan. Como del valor distinto de cero en 6,11; cel valor distinto de cero 5,11en . Y una vez que hay un valor más pequeño, entonces este valor debe haber aparecido antes, por ejemplo b[9]=4, este 4 ha aparecido antes.

Si se toma 索引降低,则索引必然重复como un principio, entonces obviamente 0y 1también puede incluirse en este principio, b,c,del 0 del medio ha aparecido en primer lugar; y ano hay un 0 en el medio, porque a[0]=1su valor mínimo solo puede ser 1.

O a[i]bien i+1, o un valor que se ha producido alguna vez.

En este caso, para una Ncadena de longitud str, puedo strextraer el Mcarácter anterior para hacer coincidir hacia atrás. Por ejemplo "ababcdabadc", haga coincidir primero para aobtener un conjunto de posiciones que coincidan con éxito; luego haga coincidir estas posiciones ab, y así sucesivamente, hasta que la posición coincidente sea la posición 0.

Supongo que te gusta

Origin blog.csdn.net/m0_37816922/article/details/124063981
Recomendado
Clasificación